名为Triple nested Forms in Rails的文章对创建用于保存三个嵌套对象的表单进行了很好的描述。给出的示例是创建一个Show
和has_many Seasons
,并且每个Season
具有多个Episodes
。另外,Episode --> belongs_to --> Season --> belongs_to --> Show
。节目是这样创建的:
def new
@show = Show.new
@show.seasons.build.episodes.build
end
表格看起来像这样:
<%= form.fields_for :seasons do |s| %>
<%= s.label :number %>
<%= s.number_field :number %> <%= s.fields_for :episodes do |e| %>
<%= e.label :title %>
<%= e.text_field :title %>
<% end %>
<% end %>
<% end %>
这似乎很简单,因为所有关联都在一个方向上运行。我正在尝试做类似但更复杂的事情。我有一个Parent
模型,其中每个Parent
具有多个Children
,并且每个Child
都注册了一个School
。在指定Children
为Child
的复数之后,关联将必须像这样:
Parent has_many Children, accepts_nested_attributes_for :children
Child belongs_to Parent, belongs_to School, accepts_nested_attributes_for :school
School has_many Children, accepts_nested_attributes_for :children
图形上看起来像这样:
Parent <-- belongs_to <-- Child --> belongs_to --> School
每个父级也与一个用户相关联,例如:
User has_many :parents
[父母,子女和学校的数据以以下形式输入(使用Simple Form gem生成),其中,作为从学校表中填充的下拉选择器输入学校:
@schools = School.all
<%= simple_form_for (@parent) do |f| %>
<%= f.input :name, label: 'name' %>
<%= f.simple_fields_for :children, @children do |child_form| %>
<%= child_form.input :name, label: "Child Name" %>
<%= child_form.simple_fields_for :school, @school do |school %>
<%= school.collection_select :id, @schools, :id, :name, {}, {} %>
<% end %>
<% end %>
<% end %>
我设置了new
控制器方法,以创建一个在现有Parent
中注册了三个Children
的School
。然后我尝试将Children
与School
表中已经存在且ID = 1的schools
关联。
def new
@parent = Parent.new
# creating 3 children
@children = Array.new(3) {@parent.children.build}
@school = School.find(1)
@school.children.build
end
这将引发错误。
Couldn't find School with ID=1 for Child with ID=
错误位于create方法的第一行,如下所示:
def create
@parent = Parent.new(parent_params.merge(:user => current_user))
if @parent.save
redirect_to root_path
else
render :new, :status => :unprocessable_entity
end
end
def parent_params
params.require(:parent).permit(:name, :child_attributes => [:id, :name, age, :school_attributes => [:id, :name]])
end
由于错误文本状态为"Child with ID= "
,因此必须在分配新Children
的ID之前引发错误。当School
表中存在ID = 1的schools
时,为什么找不到它?或者,这是否意味着在尝试保存School
实例之前,Child
记录未与该实例正确关联?如果是这样,我该如何解决该关联?
具有嵌套属性的最常见的误解/错误之一是认为您需要它来进行简单的关联分配。你不知道您只需要传递一个ID或ID数组即可。
如果用户同时创建一所学校,则只需要接受学校的嵌套属性。在那种情况下,使用Ajax而不是将所有内容塞入一个大型动作中可能是一个更好的主意。
<%= simple_form_for (@parent) do |f| %>
<%= f.input :name, label: 'name' %>
<%= f.simple_fields_for :children, @children do |child_form| %>
<%= child_form.input :name, label: "Child Name" %>
<%= child_form.associaton :school,
collection: @schools, label_method: :name %>
<% end %>
<% end %>
def parent_params
params.require(:parent).permit( :name,
child_attributes: [:id, :name, :age, :school_id]]
)
end