我正在尝试创建一个嵌套表单,其中包含选项和子选项,两者都来自名为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的一个问题,但我不确定是什么。
答案 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
,因为这更清楚地表达了它的含义。