问题描述
我需要创建一个Training
,然后在Rails 6应用程序中添加带有嵌套表单字段(茧)的Attendances
。情况如下:
模型如下:
培训模式
class Training < ApplicationRecord
has_many :attendances,dependent: :destroy
has_many :people,through: :attendances
accepts_nested_attributes_for :attendances,reject_if: :all_blank,allow_destroy: true
end
出勤模式
class Attendance < ApplicationRecord
belongs_to :training
belongs_to :person
end
人员模型
class Person < ApplicationRecord
has_many :attendances,dependent: :destroy
has_many :trainings,through: :attendances
end
如果数据库中存在Person
,则用户从下拉选择字段中选择人员的姓名。
如果Person
不存在,则用户必须通过输入人员的姓名和年龄来手动输入人员的信息。
我如何设置控制器和表格以允许用户手动输入人员的姓名和年龄,然后在保存培训后在嵌套的表格字段中自动创建该人员和出勤? strong>
解决方法
键的嵌套属性有一个id
字段。 Rails的行为是如果存在id
则更新现有记录,或者如果id
为空白则创建新记录。
基本上,这就是您需要做的。输入此人的姓名和年龄,但id
为空,将创建一个新记录。
我强烈建议您使用cocoon
宝石https://github.com/nathanvda/cocoon,它会为您的培训表格提供link_to_add_association
的帮助者,它可以自动让您打开一个新的空人表格。实施后,您将使用类似这样的方法来调用帮助程序
<%= link_to_add_association 'add attendee',f,:people %>
您可以忽略通过联接表将人员与培训相关联...在保存新人员时,rails会自动创建联接记录。
,我使用了上面评论中的链接:https://github.com/nathanvda/cocoon/wiki/A-guide-to-doing-nested-model-forms#the-look-up-or-create-belongs_to
我使用了Wiki中的最后一个示例。
这是我针对该功能的最终MVC版本的结果:
模型
class Person < ApplicationRecord
has_many :attendances,dependent: :destroy
has_many :trainings,through: :attendances
end
class Attendance < ApplicationRecord
belongs_to :training
belongs_to :person
accepts_nested_attributes_for :person,:reject_if => :all_blank
end
class Training < ApplicationRecord
has_many :attendances
has_many :people,through: :attendances
accepts_nested_attributes_for :attendances,reject_if: :all_blank,allow_destroy: true
accepts_nested_attributes_for :people
end
培训负责人
class TrainingsController < ApplicationController
put your normal controller actions here and then in
training_params put this:
def training_params
params.require(:training).permit(
attendances_attributes: [:id,:_destroy,:person_id,person_attributes: [:id,:name,:age,:program_id]]
)
end
end
将其添加到培训/表单
.row
.col.s12
.pt-5
%h6
Attendance
#people
= f.fields_for :attendances do |attendance|
= render 'attendance_fields',:f => attendance
.people_links
= link_to_add_association 'Add',:attendances
将此添加到trainings / _attendance_fields
.nested-fields.attendance-person-fields
.field
.person_from_list
= f.select(:person_id,Person.all.map { |p| [p.name,p.id] },{ include_blank: true },{ :class => 'chosen-select' })
= link_to_add_association 'Or create',:person,data: {disable_with: "creating person"}
最后在培训中/ _person_fields
.nested-fields
.input-field
= f.text_field :name
= f.label :name
.input-field
= f.number_field :age
= f.label :age
我添加了咖啡脚本:( in:person.coffee
$('#people').on('cocoon:before-insert',(e,attendance_to_be_added) ->
attendance_to_be_added.fadeIn 'slow'
return
)
$('#people a.add_fields').data('association-insertion-position','before').data 'association-insertion-node','this'
$('#people').on 'cocoon:after-insert',->
$('.attendance-person-fields a.add_fields').data('association-insertion-position','this'
$('.attendance-person-fields').on 'cocoon:after-insert',->
$(this).children('.person_from_list').remove()
$(this).children('a.add_fields').hide()
return
return