Rails 带茧的嵌套形式。使用模型的属性
Rails nested form with cocoon. Attributes using model
我正在尝试创建一个包含选项和子选项的嵌套表单,它们都来自同一个名为 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
视图已正确创建,但未保存。它在创建控制器时转到 "render :new"。我觉得应该是params的问题,但是我不确定是什么。
可能由于验证失败而未保存。如果您使用 rails 5,belongs_to
现在更严格,并且为了能够保存嵌套参数,您需要使关联之间的 connection/relation 显式。
所以恕我直言,如果您将 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
,因为这样可以更清楚地传达其含义。
我正在尝试创建一个包含选项和子选项的嵌套表单,它们都来自同一个名为 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
视图已正确创建,但未保存。它在创建控制器时转到 "render :new"。我觉得应该是params的问题,但是我不确定是什么。
可能由于验证失败而未保存。如果您使用 rails 5,belongs_to
现在更严格,并且为了能够保存嵌套参数,您需要使关联之间的 connection/relation 显式。
所以恕我直言,如果您将 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
,因为这样可以更清楚地传达其含义。