可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is there a way in strong parameters to permit all attributes of a nested_attributes model? Here is a sample code.
class Lever < ActiveRecord::Base
has_one :lever_benefit
accepts_nested_attributes_for :lever_benefit
end
class LeverBenefit < ActiveRecord::Base
# == Schema Information
# id :integer not null, primary key
# lever_id :integer
# explanation :text
end
For lever strong parameters i am writing currently this
def lever
params.require(:lever).permit(:name,:lever_benefit_attributes => [:lever_id, :explanation])
end
Is there a way for nested attributes i can write to permit all attributes without explicitly giving the attributes name like lever_id
and explanation
?
Note: Please don't get confused with this question with permit!
or permit(:all)
this is for permitting all for nested attributes
回答1:
The whole point of strong parameters is in its name: make your input parameters strong.
Permitting all the parameters would be a very bad idea, as it would permit anyone to insert values you don't necessarily want to be updated by your users.
In the example you give, you mention the two parameters you currently need to provide:
[:lever_id, :explanation]
.
If you permitted all the parameters, it would be possible for somebody to change any other value.
created_at
, or lever_id
for example.
This would definitely be a security issue and this is why you should not do it.
Explicitely specifying all your attributes might seem boring when you do it.
But this is necessary to keep your application secure.
Edit: For people downvoting this. This may not be the answer you're looking for, but it is the answer you need.
Whitelisting all nested attributes is a huge security flaw that strong params is trying to protect you with, and you're removing it.
Take a look at what lead to building strong_params, and how not using it can be bad for you: https://gist.github.com/peternixey/1978249
回答2:
The only situation I have encountered where permitting arbitrary keys in a nested params hash seems reasonable to me is when writing to a serialized column. I've managed to handle it like this:
class Post
serialize :options, JSON
end
class PostsController < ApplicationController
...
def post_params
all_options = params.require(:post)[:options].try(:permit!)
params.require(:post).permit(:title).merge(:options => all_options)
end
end
try
makes sure we do not require the presents of an :options
key.
回答3:
Actually there is a way to just white-list all nested parameters.
params.require(:lever).permit(:name).tap do |whitelisted|
whitelisted[:lever_benefit_attributes ] = params[:lever][:lever_benefit_attributes ]
end
This method has advantage over other solutions. It allows to permit deep-nested parameters.
While other solutions like:
nested_keys = params.require(:lever).fetch(:lever_benefit_attributes, {}).keys
params.require(:lever).permit(:name,:lever_benefit_attributes => nested_keys)
Don't.
Source:
https://github.com/rails/rails/issues/9454#issuecomment-14167664
回答4:
First, make sure that you really want to allow all values in a nested hash. Read through Damien MATHIEU's answer to understand the potential opening of security holes...
If you still need/want to allow all values in a hash (there are perfectly valid use cases for this, e.g. storing unstructured, user-provided metadata for a record), you can achieve it using the following bits of code:
def lever_params
nested_keys = params.require(:lever).fetch(:lever_benefit_attributes, {}).keys
params.require(:lever).permit(:name,:lever_benefit_attributes => nested_keys)
end
Note: This is very similar to tf.'s answer but a bit more elegant since you will not get any Unpermitted parameters: lever_benefit_attributes
warnings/errors.
回答5:
try
params.require(:lever).permit(:name, leave_benefit_attributes: LeaveBenefit.attribute_names.collect { |att| att.to_sym })