Ruby-on-rails Rails 4.0 强参数嵌套属性,带有指向哈希的键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14483963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails 4.0 Strong Parameters nested attributes with a key that points to a hash
提问by John
I was playing around with Rails 4.x beta and trying to get nested attributes working with carrierwave. Not sure if what I'm doing is the right direction. After searching around, and then eventually looking at the rails source and strong parameters I found the below notes.
我在玩 Rails 4.x beta 并尝试使用carrierwave 获取嵌套属性。不确定我在做什么是正确的方向。在四处搜索,然后最终查看 rails 源和强参数后,我发现了以下注释。
# Note that if you use +permit+ in a key that points to a hash, # it won't allow all the hash. You also need to specify which # attributes inside the hash should be whitelisted.
# Note that if you use +permit+ in a key that points to a hash, # it won't allow all the hash. You also need to specify which # attributes inside the hash should be whitelisted.
So its saying you have to specify every single every single attribute within the has, I tried the following:
因此,它说您必须指定 has 中的每个属性,我尝试了以下操作:
Param's example:
参数示例:
{"utf8"=>"?",
"authenticity_token"=>"Tm54+v9DYdBtWJ7qPERWzdEBkWnDQfuAQrfT9UE8VD=",
"screenshot"=>{
"title"=>"afs",
"assets_attributes"=>{
"0"=>{
"filename"=>#<ActionDispatch::Http::UploadedFile:0x00000004edbe40
@tempfile=#<File:/tmp/RackMultipart20130123-18328-navggd>,
@original_filename="EK000005.JPG",
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"screenshot[assets_attributes][0][filename]\"; filename=\"EK000005.JPG\"\r\nContent-Type: image/jpeg\r\n">
}
}
},
"commit"=>"Create Screenshot"}
Controller
控制器
def screenshot_params
params.require(:screenshot).permit(:title,
:assets_attributes => [:filename => [:@tempfile,:@original_filename,:@content_type,:@headers]
The above isn't "working" (its not triggering carrierwave) however I am no longer getting errors (Unpermitted parameters: filename) when using the standard nested examples I found ex:
以上不是“工作”(它没有触发载波)但是当使用我发现的标准嵌套示例时,我不再收到错误(不允许的参数:文件名):
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
If anyone could help it would be great. I was not able to find a example with nested with a key that points to a hash.
如果有人可以提供帮助,那就太好了。我无法找到嵌套有指向散列的键的示例。
采纳答案by Jim Deville
My other answer was mostly wrong - new answer.
我的另一个答案大多是错误的 - 新答案。
in your params hash, :filename is not associated with another hash, it is associated with an ActiveDispatch::Http::UploadedFile object. Your last code line:
在您的 params 散列中, :filename 与另一个散列无关,它与 ActiveDispatch::Http::UploadedFile 对象相关联。您的最后一行代码:
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
is actually correct, however, the filename attribute is not being allowed since it is not one of the permitted scalar types. If you open up a console, and initialize a params object in this shape:
实际上是正确的,但是,不允许使用 filename 属性,因为它不是允许的标量类型之一。如果您打开一个控制台,并以这种形状初始化一个 params 对象:
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: 'a string'}}}
and then run it against your last line:
然后针对你的最后一行运行它:
p = params.require(:screenshot).permit(:title, assets_attributes: :filename)
# => {"title" => "afa", "assets_attributes"=>{"0"=>{"filename"=>"abc"}}}
However, if you do the same against a params hash with the uploaded file, you get
但是,如果您对上传文件的 params 哈希执行相同的操作,您会得到
upload = ActionDispatch::Http::UplaodedFile.new tempfile: StringIO.new("abc"), filename: "abc"
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: upload}}}
p = params.require(:screenshot).permit(:title, assets_attributes: :filename)
# => {"title" => "afa", "assets_attributes"=>{"0"=>{}}}
So, it is probably worth a bug or pull request to Rails, and in the meantime, you will have to directly access the filename parameter using the raw paramsobject:
因此,可能值得向 Rails 提出错误或拉取请求,同时,您必须使用原始params对象直接访问文件名参数:
params[:screenshot][:assets_attributes]["0"][:filename]
回答by Pat McGee
So, you're dealing with has_many forms and strong parameters.
因此,您正在处理 has_many 形式和强参数。
This is the part of the params hash that matters:
这是重要的 params 哈希部分:
"assets_attributes"=>{
"0"=>{
"filename"=>#<ActionDispatch::Http::UploadedFile:0x00000004edbe40
@tempfile=#<File:/tmp/RackMultipart20130123-18328-navggd>,
@original_filename="EK000005.JPG",
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"screenshot[assets_attributes][0][filename]\"; filename=\"EK000005.JPG\"\r\nContent-Type: image/jpeg\r\n">
}
}
when you define strong parameters like this...
当你定义这样的强参数时......
permit(:assets_attributes => [:filename])
Things break, because where rails expects a filenameit's getting this "0"
事情坏了,因为 rails 期望filename它得到这个"0"
What does that number mean? It's the idfor the asset you are submitting via your form. Now initially you might think you have to do something like
这个数字是什么意思?这是id您通过表单提交的资产。现在最初你可能认为你必须做类似的事情
permit(:assets_attributes => [:id => [:filename]])
This looks like it follows other strong parameters syntax conventions. However, for better or for worse, they have made things a little easier, and all you have to write is:
看起来它遵循其他强参数语法约定。然而,无论好坏,它们让事情变得更容易了,你所要做的就是:
permit(:assets_attributes => [:asset_id, :filename])
Edit- As jpwynnpointed out in the comments, in Rails 4.2.4+ the correct syntax is
编辑- 正如jpwynn在评论中指出的,在 Rails 4.2.4+ 中,正确的语法是
permit(:assets_attributes => [:id, :filename])
and that should work.
这应该有效。
When you hit walls with strong params, the best thing to do is throw a debugger in your controller and test things out. params.require(:something).permit(:other_things)is just a method chain so you can try out different things on the full params hash until you find what works.
当你用强参数撞墙时,最好的办法是在你的控制器中放置一个调试器并测试一下。params.require(:something).permit(:other_things)只是一个方法链,因此您可以在完整的 params 散列上尝试不同的东西,直到找到有效的方法。
回答by cgat
try
尝试
def screenshot_params
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
end
I had this issue about a month ago and some searching around dug up this solution. It was adding the :id or :screenshot_id that fixed the problem (or both, I can't remember). This works in my code though.
大约一个月前我遇到了这个问题,一些搜索找到了这个解决方案。它添加了解决问题的 :id 或 :screenshot_id (或两者,我不记得了)。不过,这适用于我的代码。
回答by nothing-special-here
Actually there is a way to just white-list all nested parameters.
实际上有一种方法可以将所有嵌套参数列入白名单。
params.require(:screenshot).permit(:title).tap do |whitelisted|
whitelisted[:assets_attributes ] = params[:screenshot][:assets_attributes ]
end
This method has advantage over other solutions. It allows to permit deep-nested parameters.
这种方法优于其他解决方案。它允许允许深度嵌套的参数。
While other solutions like:
而其他解决方案如:
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
Don't.
别。
Source:
来源:
https://github.com/rails/rails/issues/9454#issuecomment-14167664
https://github.com/rails/rails/issues/9454#issuecomment-14167664
回答by Tunde Adetula
I had same problem just got it fixed now all you have to do is
我遇到了同样的问题,现在你所要做的就是解决它
params.require(:vehicle).permit(:user_id, assets_attributes: [:id, :image]).
Use pry gem to see what kind of attributes your asset object has makes sure theres an id and add other missing attribute, that should then work perfectly. Am using paperclip assets is my nested object inside the vehicle class and an attachment of images is added to the asset. make sure you do the validation in the model
使用 pry gem 查看您的资产对象具有什么样的属性,以确保有一个 id 并添加其他缺少的属性,然后应该可以完美地工作。我正在使用回形针资产是我在车辆类中的嵌套对象,并且将图像附件添加到资产中。确保在模型中进行验证
accepts_nested_attributes_for :assets, allow_destroy: true
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
In your view loop through the asset to get each image
在您的视图中循环遍历资产以获取每个图像
<%= @vehicle.assets.size %>
<% for asset in @vehicle.assets %>
<%=link_to image_tag (asset.image.url(:thumb)) %>
<% end %>
If am correct your problem is that asset_attributes is an array with each image having an index column and an image
如果我是正确的,你的问题是 asset_attributes 是一个数组,每个图像都有一个索引列和一个图像
Your form_for should have something similar to this and if you want you can also include preview so the upload can view their images use the bottom code for that
你的 form_for 应该有类似的东西,如果你愿意,你还可以包括预览,以便上传可以查看他们的图像,使用底部代码
<div class="field">
<h3>Vehicle Image Upload</h3>
<%= f.fields_for :assets do |asset_fields| %>
<% if asset_fields.object.new_record? %>
<p>
<%= asset_fields.file_field :image %>
</p>
<% end %>
<% end %>
</div>
<div class="field">
<h4>Vehicle Image</h4>
<%= f.fields_for :assets do |asset_fields| %>
<% unless asset_fields.object.new_record? %>
<%= link_to image_tag(asset_fields.object.image.url(:thumb)),
asset_fields.object.image.url(:original)%>
<%= asset_fields.check_box :_destroy %>
<% end %>
<% end %>
</div>
回答by gilcierweb
Sanitize before save in controller Sanitize accepts_nested_attributes_for attributes with index.
保存在控制器中之前进行清理 清理接受_nested_attributes_for 带有索引的属性。
before_action :sanitize_fields_params, :only => [:create, :update]
def sanitize_fields_params
product_free_shippings_attributes = params[:product][:product_free_shippings_attributes]
product_free_shippings_attributes.each do |index, key_value|
params[:product][:product_free_shippings_attributes]["#{index}"][:weight] = clear_decimal(key_value[:weight])
params[:product][:product_free_shippings_attributes]["#{index}"][:height] = clear_decimal(key_value[:height])
params[:product][:product_free_shippings_attributes]["#{index}"][:width] = clear_decimal(key_value[:width])
params[:product][:product_free_shippings_attributes]["#{index}"][:depth] = clear_decimal(key_value[:depth])
end
end
def clear_decimal(field)
return (field.to_s.gsub(/[^\d]/, '').to_d / 100.to_d) unless field.blank?
end

