Pylons FormEncode #validate decorator pass parameters into re-render action - pylons

I am attempting to use the validate decorator in Pylons with FormEncode and I have encountered an issue. I am attempting to validate a form on a controller action that requires parameters, and if the validation fails, the parameters aren't passed back in when the form is re-rendered. Here's an example.
def question_set(self, id):
c.question_set = meta.Session.query(QuestionSet).filter_by(id=id).first()
c.question_subjects = meta.Session.query(QuestionSubject).order_by(QuestionSubject.name).all()
return render('/derived/admin/question_set.mako')
This is the controller action that contains my form. The form will add questions to an existing question set, which is identified by id. My add question controller action looks like this:
#validate(schema=QuestionForm(), form='question_set', post_only=True)
def add_question(self):
stuff...
Now, if the validation fails FormEncode attempts to redisplay the question_set form, but it does not pass the id parameter back in, so the question set form will not render. Is it possible to pass the id back in with the #validate decorator, or do I need to use a different method to achieve what I am attempting to do?

I think the problem is that add_question() doesn't receive id argument. Try to set up your routing so that add_question() receives it not only in POST vars but also as argument and see if it fixes the issue.

I had a similar issue. I adjusted my route to include the id and it worked.

Related

Rails 5 Params / Strong Params issue

I have a RESTful API (ActionController::API) service that accepts a list of params. The RESTful service takes a JSON body request (with Content-Type of application/json). When I debug the controller/action (right after the action def) and take a peak at the params list, it appears as follows:
<ActionController::Parameters {"given_name"=>"Mark", "subdomain"=>"development", "controller"=>"user", "action"=>"create", "user"=>{"given_name"=>"Mark"}} permitted: false>
EDIT
All the request has in it (when it is passed to the controller/action -- using POSTman):
{"given_name":"Mark"}
Notice that the object contains the given_name params twice. Is this normal behavior? I did not pass a "user" object (json object) to the controller/action? What is the permitted flag?
When I try to use (right now I'm just testing RESTful call and assigning any values that the user object will except... no validations have been programmed yet):
user = User.new(params)
I get the error:
#<ActiveModel::ForbiddenAttributesError: ActiveModel::ForbiddenAttributesError>
So, I've looked everywhere for the reasoning behind this (why is there a "user" key in the params list? What is the purpose of the permitted flag? Why am I getting an error when I try to assign params)?
EDIT
After doing some testing, I change the controller name from "user_controller" to "tester_controller" and setup the routes to point to the renamed controller.
It seems the "user" object in the params list above has changed to "tester". So why does the param list contain an "object" with all the passed params with the name of the controller? If that's the case, why is it needed?
Any help would be greatly appreciated.
By default Rails in API mode wraps JSON request parameters into a hash guessing its name from controller class. That's why changing the controller from User to Tester changes "object" name. You can read details here.
So if you don't need this "object" in your params just remove :json from :format array in config\initializers\wrap_parameters.rb. Or you can use fine-grained control at the controller level as described above.
You need to specify which attributes are acceptable for mass-assignment in your controller.
def create
#user = User.new(params.require(:user).permit(:given_name))
end
This prevents malicious users from making request posts that alter attributes internal to your application, like role in the case of a user object.
As mentioned above, a better explanation can be found in the guide referring to strong parameters.
You can't pass params to constructor, because params always contain :action and :controller keys. Attributes for new objects should be put in hash under key that identify model you want to create e.g. :user. I suggest you to consult rails guides, especially chapter 7 of "Form Helpers" guide.
If you want to learn more about strong parameters there is a chapter in rails guides for that too :)

Rails Controller Params - Custom Update Method for CanCan work around

I'm trying to limit access to a certain attribute when updating.
An admin is allowed to update all of a Need anytime they want, except they can only update the Need's is_public bool only if need_state is in_progress.
CanCan doesn't allow a way to limit the update action based on specific attributes that are being set... so I thought they only way to accomplish this was to make a special method called set_is_public.
I've got my form calling to it and it's sending the following params:
{"utf8"=>"✓",
"authenticity_token"=>"2u9AZ7AJDYQrXm3LubMAxlxhjbsQ14myUTyOSyvoKzk=",
"need"=>{"id"=>"5",
"is_public"=>"true"},
"commit"=>"Set as Public"}
How do you go about updating that need in the action in the controller?
I can't figure out how to read those params in and:
Find the need based on the id;
Update its is_public attribute to the value of the is_public param.
The params you posted show a nested hashed, so you should just need to do something like :
the_need = Need.find( params["need"]["id"] )
the_need.is_public = params["need"]["is_public"]
the_need.save
I hope that helps!
Edited to add : you may need to deal with parameter restrictions, depending on your version of Rails, one technique is a before filter that does :
params.require(:need).permit(:id, :is_public)
Please clarify your question if this is not helping

Rails 2.3.4 Persisting Model on Validation Failure

I have a standard html form post that is being persisted and validated with a rails model on the server side.
For the sake of discussion, lets call this a "car" model.
When
car.save
is invoked the validators fire and set a list of fields in error within the model.
How best can I get an object back that has the fields whose validation failed removed, i.e. such that I don't have to delete the fields on the form the user entered correctly?
The validation patterns they use are great but how do I get a hook to when the validation fails such that I can delete the bogus entries from the model?
I could see manually iterating over the errors list and writing a big case statement but that seems like a hack.
In your controller, render the new action from your create action if validation fails, with an instance variable, #car populated from the user input (i.e., the params hash). Then, in your view, add a logic check (either an if block around the form or a ternary on the helpers, your choice) that automatically sets the value of the form fields to the params values passed in to #car if car exists. That way, the form will be blank on first visit and in theory only be populated on re-render in the case of error. In any case, they will not be populated unless #car is set.
EDIT:
Don't do this (see comments) but if you must here is how:
I ended up using a call to
#car.invalid?
inside of a loop to remove the invalid entries:
params[:car].each do | key, array|
if #car.errors.invalid?(key)
#car[key.to_sym] = ''
end
end
render :action=> 'new'
Note the use of the render here vs. redirect. Getting error messages to persist from the rails model validation across a redirect appears tricky, see:
Rails validation over redirect
I still feel like there should be a helper method for this or a better way.

Why can't I use a param called "action"?

Is "action" as a input field name forbidden? Because everything works except the assignment of the "action" param.
because action, controller are prohibited words.
Look around debug params
--- !map:ActiveSupport::HashWithIndifferentAccess
action: index
controller: main
so you can't use those params. Because they will be REWRITED AUTOMATICALLY
I would suggest NOT using words like action, name, method as field names as they are all attributes of the form tag and are likely to get confused when the form is posted
I agree with jbeynon, I would also say anything that has to do with CRUD(Create, Read, Update, Delete) is protected also.
I don't see why this would be invalid. You'd want to avoid conflicting with existing class or method names (e.g. not a good idea to define a method called action on a controller).
everything works except the assignment
of the "action" param.
Does this generate an error? If so, what exactly?

Ruby on Rails: How do I pass a variable along with f.submit?

Ruby on Rails: How do I pass a variable along with f.submit?
no you can't pass along with submit button.
but you get name of button as params[:commit] in controller
The parameters you'rer passing would be the data in the form, yes?
What parameter/data are you trying to receive? If you want to know the name of the user who performed the submit, or the current time, or something similar, there are other ways to do it.
As Salil mentioned, the parameters/form data are accessible in the controller via the "params" array.

Resources