【问题标题】:What parameters does Rails expect for editing nested models?Rails 期望编辑嵌套模型的参数是什么?
【发布时间】:2014-04-18 01:29:53
【问题描述】:

问题

在通过 Rails 4 中的表单成功创建嵌套模型后(在 Cocoon gem 的帮助下),我现在尝试进一步扩展——在创建嵌套模型后对其进行编辑。

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

标记

<%= 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)。

(例如,我考虑了一些解决方法 - 切换到特定模型以覆盖嵌套模型,然后将其映射回来 - 但我想深入了解为什么它的行为不像我想要的那样提高我对 Rails 内部的知识。)

提前感谢您的帮助!

【问题讨论】:

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


    【解决方案1】:

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

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

    把控制器代码改成这样:

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

    解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2023-03-13
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多