Rails 4 中的嵌套表单似乎不起作用

nested forms in Rails 4 doesn't seem to work

我关注这个已经太久了,所以开始吧。

在此处关注:http://guides.rubyonrails.org/form_helpers.html#nested-forms

这是一些代码:

collection.rb

class Collection < ActiveRecord::Base
    has_many :collections_components, dependent: :destroy
    accepts_nested_attributes_for :collections_components, allow_destroy: true
end

collections_component.rb

class CollectionsComponent < ActiveRecord::Base
    belongs_to :collection
end

_form.html.erb

<%= form_for @collection do |f| %>
  <% if @collection.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@collection.errors.count, "error") %> prohibited this collection from being saved:</h2>

      <ul>
      <% @collection.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>

  <%= f.fields_for :collection_components do |collection_components_form| %>
    <h2>Collection</h2>
    <%= collection_components_form.label :text %>
    <%= collection_components_form.text_field :text %>
  <% end %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

collections_controller.rb

class CollectionsController < ApplicationController
  before_action :set_collection, only: [:show, :edit, :update, :destroy]

  def index
    @collections = Collection.all
  end

  def show
  end

  def new
    @collection = Collection.new
    3.times { @collection.collections_components.build }
  end

  def edit
  end

  def create
    @collection = Collection.new(collection_params)

    respond_to do |format|
      if @collection.save
        format.html { redirect_to @collection, notice: 'Collection was successfully created.' }
        format.json { render :show, status: :created, location: @collection }
      else
        format.html { render :new }
        format.json { render json: @collection.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @collection.update(collection_params)
        format.html { redirect_to @collection, notice: 'Collection was successfully updated.' }
        format.json { render :show, status: :ok, location: @collection }
      else
        format.html { render :edit }
        format.json { render json: @collection.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @collection.destroy
    respond_to do |format|
      format.html { redirect_to collections_url, notice: 'Collection was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_collection
      @collection = Collection.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def collection_params
      params.require(:collection).permit(:name, collections_components_attributes: [:text])
    end
end

您需要显示所有 collections_components 的表格。变化:

<%= f.fields_for :collection_components do |collection_components_form| %>
  <h2>Collection</h2>
  <%= collection_components_form.label :text %>
  <%= collection_components_form.text_field :text %>
<% end %>

至:

<% @collection.collection_components.each do |collections_component| %>
  <%= f.fields_for :collection_components, collections_component do |collection_components_form| %>
    <h2>Collection</h2>
    <%= collection_components_form.hidden_field :id %>
    <%= collection_components_form.label :text %>
    <%= collection_components_form.text_field :text %>
  <% end %>
<% end %>

id 的隐藏字段是更新所必需的。还要确保它包含在强参数中。

编辑:

我在使用 Rails 4.0.8 时遇到了这个问题。该版本的文档 suggests this solution with each。 Rails 4.2.0 的文档开始建议只使用 fields_for。我怀疑 fields_for 在 4.2.0 中直接开始处理集合,尽管我找不到它的任何更改日志。

我认为这可能是问题所在,您在 _form 中将资源称为单数而不是复数(在集合名称的中间)

<%= f.fields_for :collection_components do |collection_components_form| %> 

而不是这个:

<%= f.fields_for :collections_components do |collection_components_form| %>

也就像我一直在使用 nested_forms 之前我知道你需要传递 "id" 并且只有当你允许销毁属性时才将“_destroy”参数传递给 strong_parameters,所以你加上它就好了

def collection_params
  params.require(:collection).permit(:name, collections_components_attributes: [:text])
end

所以你应该有这样的东西:

def collection_params
  params.require(:collection).permit(:name, {collections_components_attributes: [:id, :text, :_destroy]})
end

另外我会推荐这个 railscasts for future research and an excelent gem called cocoon 来轻松 [​​=28=]

希望对您有所帮助!