Rails 4.0 Strong Parameters嵌套属性,带有指向哈希的键

Joh*_*ohn 34 ruby ruby-on-rails strong-parameters ruby-on-rails-4

我正在玩Rails 4.x beta并尝试使用carrierwave获取嵌套属性.不确定我正在做的是正确的方向.搜索后,最后查看导轨源和强参数,我发现了下面的注释.

# 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.
Run Code Online (Sandbox Code Playgroud)

https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/strong_parameters.rb

所以它说你必须在has中指定每一个单独的属性,我尝试了以下内容:

帕拉姆的例子:

{"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"}
Run Code Online (Sandbox Code Playgroud)

调节器

def screenshot_params
  params.require(:screenshot).permit(:title,
    :assets_attributes => [:filename => [:@tempfile,:@original_filename,:@content_type,:@headers] 
Run Code Online (Sandbox Code Playgroud)

以上不是"工作"(它不触发载波)但是当我使用我发现的标准嵌套示例时,我不再收到错误(未经许可的参数:文件名):

def screenshot_params
  params.require(:screenshot).permit(:title, assets_attributes: :filename)
Run Code Online (Sandbox Code Playgroud)

如果有人能提供帮助就会很棒.我无法找到嵌套了一个指向哈希的键的示例.

Jim*_*lle 33

我的另一个答案大多是错误的 - 新答案.

在你的params散列中,:filename与另一个散列没有关联,它与一个ActiveDispatch :: Http :: UploadedFile对象相关联.你的上一个代码行:

def screenshot_params
  params.require(:screenshot).permit(:title, assets_attributes: :filename)
Run Code Online (Sandbox Code Playgroud)

实际上是正确的,但是不允许使用filename属性,因为它不是允许的标量类型之一.如果打开控制台,并初始化此形状的params对象:

params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: 'a string'}}}
Run Code Online (Sandbox Code Playgroud)

然后在最后一行上运行它:

p = params.require(:screenshot).permit(:title, assets_attributes: :filename)
# => {"title" => "afa", "assets_attributes"=>{"0"=>{"filename"=>"abc"}}}
Run Code Online (Sandbox Code Playgroud)

但是,如果你对上传文件的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"=>{}}}
Run Code Online (Sandbox Code Playgroud)

因此,它可能值得对Rails提出错误或拉取请求,同时,您必须使用原始params对象直接访问filename参数:

params[:screenshot][:assets_attributes]["0"][:filename]
Run Code Online (Sandbox Code Playgroud)


Pat*_*Gee 14

所以,你正在处理has_many表单和强参数.

这是params hash的一部分:

"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">
 }
}
Run Code Online (Sandbox Code Playgroud)

当你定义像这样的强参数时......

permit(:assets_attributes => [:filename]) 
Run Code Online (Sandbox Code Playgroud)

事情破裂了,因为rails希望filename它能够实现这一目标"0"

这个数字是什么意思?这是id您通过表单提交的资产.现在最初你可能认为你必须做类似的事情

permit(:assets_attributes => [:id => [:filename]])
Run Code Online (Sandbox Code Playgroud)

这看起来遵循其他强参数语法约定.但是,无论好坏,他们都会让事情变得更容易,而你所要写的就是:

permit(:assets_attributes => [:asset_id, :filename])
Run Code Online (Sandbox Code Playgroud)

编辑 - 正如jpwynn在评论中指出的那样,在Rails 4.2.4+中,正确的语法是

permit(:assets_attributes => [:id, :filename])
Run Code Online (Sandbox Code Playgroud)

这应该工作.

当您使用强大的参数击中墙壁时,最好的办法是在控制器中抛出调试器并进行测试.params.require(:something).permit(:other_things)只是一个方法链,所以你可以在完整的params哈希上尝试不同的东西,直到找到有效的方法.


cga*_*gat 6

尝试

def screenshot_params
  params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
end
Run Code Online (Sandbox Code Playgroud)

大约一个月前我遇到过这个问题,有些人正在寻找这个解决方案.它正在添加:id或:screenshot_id来修复问题(或两者,我都记不清了).这虽然适用于我的代码.