如果对象在 Rails 6 中以嵌套形式不存在,如何创建对象?
Posted
技术标签:
【中文标题】如果对象在 Rails 6 中以嵌套形式不存在,如何创建对象?【英文标题】:How to create an object if it does not exist in a nested form in Rails 6? 【发布时间】:2020-12-30 07:04:02 【问题描述】:我需要创建一个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
不存在,则用户必须通过输入此人的姓名和年龄来手动输入此人的信息。
如何设置控制器和表单以允许用户手动输入人员的姓名和年龄,然后在保存培训时在嵌套表单字段中自动创建该人员和出勤?强>
【问题讨论】:
这是我在这里描述的示例之一:github.com/nathanvda/cocoon/wiki/…,并且也在示例项目github.com/nathanvda/cocoon_simple_form_demo中进行了演示 这些链接显示了如何做到这一点。对于这种情况,它是 wiki 末尾的 has_many 到示例的最后一个示例。 【参考方案1】:关键在于嵌套属性有一个id
字段。 Rails 的行为是在 id
存在时更新现有记录,或者在 id
为空时创建新记录。
本质上,这就是您需要做的所有事情。输入此人的姓名和年龄,但将 id
留空,系统将创建一条新记录。
我强烈推荐cocoon
gem https://github.com/nathanvda/cocoon,它将为您的培训表单提供link_to_add_association
助手,自动让您打开一个新的空人表单。实施后,您将使用类似这样的方式调用帮助程序
<%= link_to_add_association 'add attendee', f, :people %>
您可以忽略此人通过联接表与培训相关联...当您保存新人员时,rails 将自动创建联接记录。
【讨论】:
是的,但这里的情况是我的茧链接是这样的:link_to_add_association '添加出勤率', f, :attendances。因此,我正在创建一个出勤(在本例中为连接表)并同时在培训表单中创建一个人。 我认为这需要使用first_or_create方法 不要做f.attendance
做f.people
你可以忽略出勤,只加人。【参考方案2】:
我使用了上面评论中的链接: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, :_destroy, :name, :age, :program_id]]
)
end
end
将此添加到培训/_form
.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', f, :attendances
将此添加到培训/_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', f, :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
我添加了咖啡脚本:(在: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', 'before').data 'association-insertion-node', 'this'
$('.attendance-person-fields').on 'cocoon:after-insert', ->
$(this).children('.person_from_list').remove()
$(this).children('a.add_fields').hide()
return
return
【讨论】:
以上是关于如果对象在 Rails 6 中以嵌套形式不存在,如何创建对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何处理对尚不存在的对象的 ID 引用的 RestKit 嵌套数组?
如何在 Spring Boot Rest API 中以 XML 形式返回对象列表