在Rails中创建嵌套的两级表单

时间:2015-07-09 17:05:09

标签: ruby-on-rails forms nested-forms cocoon-gem

我有一个Restaurant模型,其中包含许多DishCategory个,并且还有Dish个到DishCategory的{​​{1}}个。{例如,类别晚餐将是与其相关的一些菜肴。为了帮助构建表单,我正在使用cocoon gem。

我熟悉为传统的嵌套表单设置视图代码,但现在我要更深入一层,我不知道如何编写以及在哪里放置菜肴的输入。我是否在我的部分内为simple_fields_for设置了另一个dishes块?按照文档,这是当前设置的方式:

模型

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>

3 个答案:

答案 0 :(得分:1)

所以看起来我确实需要创建一个额外的部分。根据我的理解,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>

注意:

当涉及到餐馆控制器代码时,它可能会让人们吵醒你的params白名单。将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

答案 1 :(得分:0)

是的,您需要在部分菜单中使用simple_fields_for。并且不要忘记在DishCategory模型中使用accepts_nested_attributes_for:菜肴。

答案 2 :(得分:0)

我有同样的问题,因为我努力让茧工作两个级别的has_many关联。就我而言,问题最终源于将茧与Trailblazer的改革形式对象结合使用。我发布了一个答案,以防其他人遇到同样的问题。

问题(这里:https://github.com/nathanvda/cocoon/blob/master/lib/cocoon/view_helpers.rb#L95)是cocoon将关联对象的嵌套字段基于模型的纯实例,而不是包含在Reform表单对象中的模型。 (不是批评,只是它的设计方式。)在你希望为嵌套对象上的关联渲染字段之前,这很好,因为嵌套属性的设置是在你的Reform表单对象中定义的,不是你的模特。

表单中的f.object基本上是实际模型,而不是表单对象。除非模型本身配置了accept_nested_attributes,否则fields_for不会将该属性视为nested_attributes_association,并且html标记不会将这些字段命名为reform-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) } %>

(可能有更好的方法来获得相关的改革表格,但这给出了这个想法)。