问题
I'm working on a Rails app and I have several actions( #delete_later, #ban_later and so on) where I only set one attribute from the request parameter( specifically, a reason
field for doing that action).
I was wondering if it is ok to do it like this:
def ban_later
@object.reason = params[:object][:reason]
@object.save
end
Or is it a best practice to use strong params even in this situation?
def ban_later
@object.reason = object_params[:reason]
@object.save
end
private
def object_params
params.require(:object).permit(:permitted_1, :permitted_2, :reason)
end
Which of these solutions is the best one? If none of them is, then what's the best solution to my problem?
Later Edit:
The #ban_later, #delete_later actions can indeed set a flag column status
but that can be done without receiving it's value from the params hash. Since you will only set one status per method you can simply set the status "pending_delete" when you are in #delete_later and "pending_ban" when you are in #ban_later.
Later Later Edit
Why use #save
and not update_attributes
directly? Let's say you need to have a if @object.save
statement. On the false branch( object not saved) you might still want to render a view where the contents of that @object
are used.
回答1:
First one saves computation.
Second one checks for existence of :object sub-hash, which I think is good for fault-tolerance.
I initially would pick the 1st, but after some thought I liked the second one more.
回答2:
The simplest answer is that if you only use one parameter in params
, and do not pass it to a multi attribute setter like model#create
then you don't have to use strong_parameters to get a secure solution.
However, I expect that it is unlikely that this is the case for the whole controller. Where the ban_later
method only needs one parameter, other controller methods will need more. In this case the question becomes: "do you want to handle params
differently for ban_later
to how you use it for the other controller methods?".
Also can you be sure that the functionality will not change, and that when you change the functionality, that you'll remember to change the way params
is handled.
Therefore, I would use strong_parameters because it means:
- parameters are handled consistently across all methods in the controller.
- changes to methods are less likely to expose vulnerabilities as functionality changes.
回答3:
If you're updating a single attribute, why don't you use the update_attributes method? (update_attribute
doesn't invoke validation)
def ban_later
@object.update_attributes reason: params(:reason)
end
private
def params params
params = %i(:permitted_1, :permitted_2, :permitted_3) unless params
params.require(:object).permit params
end
In light of the comments by ReggieB
, you could also use the update
option:
def ban_later
@object.update reason: params(:reason)
end
As mentioned, Reggie and the other answers explain the schematics of how this works best (IE with mass-assignment
etc). Above is actionable code which you're free to use.
The bottom line here is that if you want to keep your application versatile (IE having ultimate extensibility wherever you need), you'll need to adhere to the strong params setup.
The other answers outline how that setup works, and how its functionality is different dependent on what you need.
I have included a trick to make it so you only accept specific params in your params method. I've not tested it extensively, so we may have to refactor it to get the required result.
回答4:
After strong parameters check why not just update
the object? Its just a standart workflow. (Please tell me if there are any reasons not to do that in your situation)
def ban_later
@object.update(object_params)
# dont forget validation check
end
private
def object_params
params.require(:object).permit(:permitted_1, :permitted_2, :reason)
end
In this case it'd be much easier to add more updateble fields.
来源:https://stackoverflow.com/questions/33095241/should-we-use-strong-params-when-we-update-only-one-attribute