Rails期望编辑嵌套模型的参数是什么?

时间:2014-04-18 01:29:54

标签: ruby-on-rails nested-forms strong-parameters

问题

在Rails 4中创建嵌套模型(在Cocoon gem的帮助下)取得一些成功之后,我现在正试图进一步扩展 - 在创建它们之后编辑这些嵌套模型。 / p>

当我尝试更新有两个孩子的父母时 - 表单中没有进行任何实际更改,它已被加载,然后立即再次保存 - 更新未成功,我有一个验证错误,新渲染的编辑表单中的子项看起来不正确。

标记

<%= form_for @parent do |f| %>
  <%= f.fields_for :children do |builder| %>
    <%= builder.label :some_property %>  
    <%= builder.text_field :some_property %>      
    <%= builder.label :some_other_property %>  
    <%= builder.text_field :some_other_property %>      
  <% end %>
<% end %>

控制器操作

def update
  @parent = Parent.find(params[:id])
  if (@parent.update(parent_params))
    redirect_to somewhere
  else
    flash.now[:error] = "Oops, this didn't work."
    render 'edit'
  end
end

def parents_params        
  params.require(:parent).
    permit(:id, child_attributes: [:id, :some_property, :some_other_property, :_destroy])
end 

传递给控制器​​的参数

--- !ruby/hash:ActionController::Parameters
utf8: ✓
_method: patch
authenticity_token: // blah
parent: !ruby/hash:ActionController::Parameters
  children_attributes: !ruby/hash:ActionController::Parameters
    '0': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
      some_property: FOO
      some_other_property: 46
      _destroy: 'false'
      id: '8'
    '1': !ruby/hash:ActiveSupport::HashWithIndifferentAccess
      some_property: BAR
      some_other_property: 25
      _destroy: 'false'
      id: '9'
commit: Save
action: update
controller: parents
id: '3'

验证失败

此验证失败,声称孩子不是唯一的。

# from child.rb
validates :some_property, uniqueness: true

摘要

此表单在保存第一个孩子(甚至是多个孩子)时可以正常工作,重新访问该页面并尝试再次保存 以解决问题。

请注意,当表单呈现第二个时间(保存失败后)时,它现在包含第二个孩子的详细信息,两次结束(即BAR / 25),因为只有两个孩子

(我考虑了一些变通方法 - 转换到特定模型以覆盖嵌套模型,然后将其映射回来 - 例如 - 但我想深究为什么这不是&#39 ; t表现得像我想提高我对rails内部的知识。)

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我找到了解决方案(在绝望中添加一些调试代码并看到我的测试突然过去了!)。

出于某种原因,在控制器中,加载父级还没有完全加载现有的子级,因此新的子级被错误识别。

将控制器代码更改为:

def update
  # This is the key line - note the additional .includes
  @parent = Parent.includes(:children).find(params[:id])

  if (@parent.update(parent_params))
  ...
end

解决了这个问题。