Rails 4.0 Strong参数使用指向散列的键来嵌套属性
我正在玩Rails 4.xtesting版,并尝试使用carrierwave来获取嵌套属性。 不知道我在做什么是正确的方向。 经过四周search,然后最终看到了轨道来源和强大的参数,我发现下面的笔记。
# 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.
https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/strong_parameters.rb
所以它说你必须指定每一个单一的属性,我试着以下几点:
帕拉姆的例子:
{"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"}
调节器
def screenshot_params params.require(:screenshot).permit(:title, :assets_attributes => [:filename => [:@tempfile,:@original_filename,:@content_type,:@headers]
上面是不是“工作”(它不触发载波),但是当我使用标准的嵌套的例子,我不再犯错误(不允许的参数:文件名)我发现前:
def screenshot_params params.require(:screenshot).permit(:title, assets_attributes: :filename)
如果有人能帮上忙,那就太好了。 我无法find与指向散列的键嵌套的示例。
我的其他答案大多是错误的 – 新的答案。
在你的params散列中,:filename不与另一个散列关联,它与一个ActiveDispatch :: Http :: UploadedFile对象相关联。 你的最后一行代码:
def screenshot_params params.require(:screenshot).permit(:title, assets_attributes: :filename)
实际上是正确的,但是文件名属性不被允许,因为它不是允许的标量types之一 。 如果你打开一个控制台,并初始化这个形状的params对象:
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: 'a string'}}}
然后在最后一行运行它:
p = params.require(:screenshot).permit(:title, assets_attributes: :filename) # => {"title" => "afa", "assets_attributes"=>{"0"=>{"filename"=>"abc"}}}
但是,如果你对上传文件的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"=>{}}}
所以,这可能是值得Rails的错误或拉取请求,同时,你将不得不使用原始params
对象直接访问filename参数:
params[:screenshot][:assets_attributes]["0"][:filename]
所以,你正在处理has_manyforms和强大的参数。
这是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"> } }
当你定义这样的强参数…
permit(:assets_attributes => [:filename])
事情打破,因为哪里的铁轨期望一个filename
就得到这个"0"
这个数字是什么意思? 这是您通过表单提交的资产的id
。 现在最初你可能会认为你必须做类似的事情
permit(:assets_attributes => [:id => [:filename]])
这看起来像遵循其他强大的参数语法约定。 然而,无论好坏,他们已经使事情变得更容易一些,你所要写的是:
permit(:assets_attributes => [:asset_id, :filename])
编辑 – 正如jpwynn在评论中指出的,在Rails 4.2.4 +中,正确的语法是
permit(:assets_attributes => [:id, :filename])
这应该工作。
当你用强参数打墙时,最好的办法是在你的控制器中放一个debugging器,然后testing一下。 params.require(:something).permit(:other_things)
只是一个方法链,所以你可以在完整的参数哈希上尝试不同的东西,直到find有效的东西。
尝试
def screenshot_params params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id]) end
大约一个月前我曾经遇到过这个问题,有些人在search这个解决scheme。 这是添加:ID或:screenshot_id修复问题(或两者,我不记得)。 这在我的代码虽然工作。
实际上有一种方法可以将所有嵌套的参数白名单。
params.require(:screenshot).permit(:title).tap do |whitelisted| whitelisted[:assets_attributes ] = params[:screenshot][:assets_attributes ] end
这种方法比其他解决scheme有优势。 它允许允许深嵌套的参数。
而其他解决scheme如:
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
别。
资源:
https://github.com/rails/rails/issues/9454#issuecomment-14167664
我有同样的问题,现在只需要修理就可以了
params.require(:vehicle).permit(:user_id, assets_attributes: [:id, :image]).
使用撬gem,看看你的资产对象有什么样的属性确保一个ID和添加其他缺less的属性,那应该是完美的。 我使用回形针资产是车辆类中的嵌套对象,图像附件被添加到资产中。 确保你在模型中进行validation
accepts_nested_attributes_for :assets, allow_destroy: true validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
在你的视图循环通过资产来获取每个图像
<%= @vehicle.assets.size %> <% for asset in @vehicle.assets %> <%=link_to image_tag (asset.image.url(:thumb)) %> <% end %>
如果更正您的问题是,asset_attributes是一个数组与每个图像具有索引列和图像
你的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>
在保存在控制器中之前进行清理对具有索引的属性进行sanitize accep_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