在 Rails 中创建嵌套的两级表单
Creating a nested two level form in Rails
我有一个 Restaurant
模型,它有很多 DishCategory
,也有很多 Dish
到 DishCategory
。因此,例如,类别 Dinner 将是与其关联的一些菜肴。为了帮助构建表单,我正在使用 cocoon gem.
我熟悉为传统的嵌套表单设置视图代码,但现在我要更深入一层,我不确定如何编写以及将菜肴的输入放在哪里。我是否在部分内容中为 dishes
设置了另一个 simple_fields_for
块?按照文档,这是目前的设置方式:
型号
class Restaurant < ActiveRecord::Base
has_many :dish_categories, dependent: :destroy
has_many :dishes, through: :dish_categories, dependent: :destroy
accepts_nested_attributes_for :dish_categories, :reject_if => :all_blank, :allow_destroy => true
end
class DishCategory < ActiveRecord::Base
belongs_to :restaurant
has_many :dishes, dependent: :destroy
accepts_nested_attributes_for :dishes, :reject_if => :all_blank, :allow_destroy => true
end
class Dish < ActiveRecord::Base
belongs_to :dish_category
end
餐厅表格
<%= simple_form_for(@restaurant) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :name %>
</div>
<div class="form-inputs dish-category-inputs">
<%= f.simple_fields_for :dish_categories do |f| %>
<%= render 'dish_category_fields', f: f %>
<% end %>
</div>
<div class='add-dish-category'>
<%= link_to_add_association 'Add a Dish Category', f, :dish_categories %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
菜肴类别字段
<div class="dish-category-form nested-fields">
<%= f.input :name %>
<%= link_to_remove_association "Remove Category", f %>
</div>
是的,您需要使用 simple_fields_for 来制作部分菜肴。并且不要忘记在 DishCategory 模型中使用 accepts_nested_attributes_for :dishes。
所以看起来我确实需要创建一个额外的部分。据我了解,links_to_add_association
中的第三个参数需要与您希望嵌套的表单的模型关联的部分。
菜肴类别字段
<div class="dish-category-form nested-fields">
<%= f.input :name %>
<%= link_to_remove_association "Remove Category", f %>
</div>
<div class="form-inputs dish-category-inputs">
<%= f.simple_fields_for :dishes do |f| %>
<%= render "dish_fields", f: f %>
<% end %>
</div>
<div class='add-dish'>
<%= link_to_add_association "Add Dish", f, :dishes %>
</div>
菜田
<div class="dish-category-form nested-fields">
<%= f.input :name %>
<%= link_to_remove_association "Remove Dish", f %>
</div>
注意:
当涉及到餐厅控制器代码时,它可能会让人们误以为将您的参数列入白名单。将 dishes_attributes
放在 dish_categories_attributes
中很重要,以便正确保存所有内容:
餐厅管理员
class RestaurantsController < ApplicationController
...
private
def restaurant_params
params.require(:restaurant).permit(:name, dish_categories_attributes: [:id, :restaurant_id, :name, :_destroy, dishes_attributes: [:id, :dish_category_id, :name, :description, :_destroy]])
end
end
我有同样的问题,因为我努力让 cocoon 与两个级别的 has_many 关联一起工作。就我而言,问题最终源于将 cocoon 与 Trailblazer 的 Reform 表单对象结合使用。我发布了一个答案,以防其他人遇到同样的问题。
问题(此处:https://github.com/nathanvda/cocoon/blob/master/lib/cocoon/view_helpers.rb#L95)是 cocoon 将关联对象的嵌套字段基于模型的纯实例,而不是包裹在 Reform 表单对象中的模型。 (不是批评,只是它的设计方式。)这很好,直到您想要为该嵌套对象 on 上的关联呈现字段,因为嵌套属性的设置在您的 Reform 中定义表单对象,而不是您的模型。
基本上 f.object
在您的表单部分中是实际模型,而不是表单对象。除非模型本身配置了 accept_nested_attributes,否则 fields_for
不会将属性视为 nested_attributes_association
并且 html 标记不会以这样的方式命名字段-rails 可以将它们解析为正确嵌套的参数。
我的解决方案是使用 wrap_object
来确保 Cocoon 使用的记录是包装在相关表单对象中的模型,如下所示:
<%= link_to_add_association 'Add Supporting Image', f, :images, partial: 'web_app/report/supporting_image_fields', force_non_association_create: true, wrap_object: Proc.new {|image| Report::WebAppCreation::ImageWithoutHotspotsForm.new(image) } %>
(可能有更好的方法来获取相关的改革表格,但这提供了思路)。
我有一个 Restaurant
模型,它有很多 DishCategory
,也有很多 Dish
到 DishCategory
。因此,例如,类别 Dinner 将是与其关联的一些菜肴。为了帮助构建表单,我正在使用 cocoon gem.
我熟悉为传统的嵌套表单设置视图代码,但现在我要更深入一层,我不确定如何编写以及将菜肴的输入放在哪里。我是否在部分内容中为 dishes
设置了另一个 simple_fields_for
块?按照文档,这是目前的设置方式:
型号
class Restaurant < ActiveRecord::Base
has_many :dish_categories, dependent: :destroy
has_many :dishes, through: :dish_categories, dependent: :destroy
accepts_nested_attributes_for :dish_categories, :reject_if => :all_blank, :allow_destroy => true
end
class DishCategory < ActiveRecord::Base
belongs_to :restaurant
has_many :dishes, dependent: :destroy
accepts_nested_attributes_for :dishes, :reject_if => :all_blank, :allow_destroy => true
end
class Dish < ActiveRecord::Base
belongs_to :dish_category
end
餐厅表格
<%= simple_form_for(@restaurant) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :name %>
</div>
<div class="form-inputs dish-category-inputs">
<%= f.simple_fields_for :dish_categories do |f| %>
<%= render 'dish_category_fields', f: f %>
<% end %>
</div>
<div class='add-dish-category'>
<%= link_to_add_association 'Add a Dish Category', f, :dish_categories %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
菜肴类别字段
<div class="dish-category-form nested-fields">
<%= f.input :name %>
<%= link_to_remove_association "Remove Category", f %>
</div>
是的,您需要使用 simple_fields_for 来制作部分菜肴。并且不要忘记在 DishCategory 模型中使用 accepts_nested_attributes_for :dishes。
所以看起来我确实需要创建一个额外的部分。据我了解,links_to_add_association
中的第三个参数需要与您希望嵌套的表单的模型关联的部分。
菜肴类别字段
<div class="dish-category-form nested-fields">
<%= f.input :name %>
<%= link_to_remove_association "Remove Category", f %>
</div>
<div class="form-inputs dish-category-inputs">
<%= f.simple_fields_for :dishes do |f| %>
<%= render "dish_fields", f: f %>
<% end %>
</div>
<div class='add-dish'>
<%= link_to_add_association "Add Dish", f, :dishes %>
</div>
菜田
<div class="dish-category-form nested-fields">
<%= f.input :name %>
<%= link_to_remove_association "Remove Dish", f %>
</div>
注意:
当涉及到餐厅控制器代码时,它可能会让人们误以为将您的参数列入白名单。将 dishes_attributes
放在 dish_categories_attributes
中很重要,以便正确保存所有内容:
餐厅管理员
class RestaurantsController < ApplicationController
...
private
def restaurant_params
params.require(:restaurant).permit(:name, dish_categories_attributes: [:id, :restaurant_id, :name, :_destroy, dishes_attributes: [:id, :dish_category_id, :name, :description, :_destroy]])
end
end
我有同样的问题,因为我努力让 cocoon 与两个级别的 has_many 关联一起工作。就我而言,问题最终源于将 cocoon 与 Trailblazer 的 Reform 表单对象结合使用。我发布了一个答案,以防其他人遇到同样的问题。
问题(此处:https://github.com/nathanvda/cocoon/blob/master/lib/cocoon/view_helpers.rb#L95)是 cocoon 将关联对象的嵌套字段基于模型的纯实例,而不是包裹在 Reform 表单对象中的模型。 (不是批评,只是它的设计方式。)这很好,直到您想要为该嵌套对象 on 上的关联呈现字段,因为嵌套属性的设置在您的 Reform 中定义表单对象,而不是您的模型。
基本上 f.object
在您的表单部分中是实际模型,而不是表单对象。除非模型本身配置了 accept_nested_attributes,否则 fields_for
不会将属性视为 nested_attributes_association
并且 html 标记不会以这样的方式命名字段-rails 可以将它们解析为正确嵌套的参数。
我的解决方案是使用 wrap_object
来确保 Cocoon 使用的记录是包装在相关表单对象中的模型,如下所示:
<%= link_to_add_association 'Add Supporting Image', f, :images, partial: 'web_app/report/supporting_image_fields', force_non_association_create: true, wrap_object: Proc.new {|image| Report::WebAppCreation::ImageWithoutHotspotsForm.new(image) } %>
(可能有更好的方法来获取相关的改革表格,但这提供了思路)。