Rails嵌套形式与茧。使用模型

时间:2017-01-09 22:01:46

标签: ruby-on-rails nested-forms has-many belongs-to cocoon-gem

我正在尝试创建一个嵌套表单,其中包含选项和子选项,两者都来自名为Option的同一模型。以下是文件的内容:

型号:

class Option < ApplicationRecord
  belongs_to :activity
  has_many :option_students
  has_many :students, through: :option_students

  has_many :suboptions,
    class_name: "Option",
    foreign_key: "option_id"

  belongs_to :parent,
    class_name: "Option",
    optional: true,
    foreign_key: "option_id"

  accepts_nested_attributes_for :suboptions,

    reject_if: ->(attrs) { attrs['name'].blank? }

  validates :name, presence: true
end

控制器:

class OptionsController < ApplicationController
  include StrongParamsHolder

  def index
    @options = Option.where(option_id: nil)
  end

  def show
    @option = Option.find(params[:id])
  end

  def new
    @option = Option.new()
    1.times { @option.suboptions.build}
  end

  def create
    @option = Option.new(option_params)
    if @option.save
      redirect_to options_path
    else
      render :new
    end
  end

  def edit
    @option = Option.find(params[:id])
  end

  def update
    @option = Option.find(params[:id])
    if @option.update_attributes(option_params)
      redirect_to options_path(@option.id)
    else
      render :edit
    end
  end

  def destroy
    @option = Option.find(params[:id])
    @option.destroy
    redirect_to options_path
  end

end

_form.html.erb:

<%= form_for @option do |f| %>

  <p>
    <%= f.label :name %><br>
    <%= f.text_field :name %><br>
    <%= f.label :activity %><br>
    <%= select_tag "option[activity_id]", options_for_select(activity_array) %><br>
  </p>

  <div>
    <div id="suboptions">
      <%= f.fields_for :suboptions do |suboption| %>
        <%= render 'suboption_fields', f: suboption %>
      <% end %>

      <div class="links">
        <%= link_to_add_association 'add suboption', f, :suboptions %>
      </div>
    </div>
  </div>

  <p>
    <%= f.submit "Send" %>
  </p>
<% end %>

_suboption_fields.html.erb

<div class="nested-fields">
  <%= f.label :suboption %><br>
  <%= f.text_field :name %>
  <%= link_to_remove_association "X", f %>
</div>

StrongParamsHolder:

def option_params
    params.require(:option).permit(:name, :activity_id, :students_ids => [], suboptions_attributes: [:id, :name])
end

视图已正确创建,但未保存。它转到create controller上的“render:new”。我认为它应该是params的一个问题,但我不确定是什么。

1 个答案:

答案 0 :(得分:3)

由于验证失败,可能无法保存。如果您正在使用rails 5,belongs_to现在更加严格,并且为了能够保存嵌套参数,您需要使关联之间的连接/关系显式化。

因此,如果您将inverse_of添加到您的关系中,它将起作用,如下所示:

has_many :suboptions,
  class_name: "Option",
  foreign_key: "option_id",
  inverse_of: :parent 

belongs_to :parent,
  class_name: "Option",
  optional: true,
  foreign_key: "option_id"
  inverse_of: :suboptions

如果其他验证失败,它也可能有助于列出表单中的错误(例如@option.errors.full_messages.inspect会有所帮助:)

暂且不说:我会将数据库中的option_id字段重命名为parent_id,因为这更清楚地表达了它的含义。