我在理解accepts_nested_attributes_for时遇到了一些挑战。
我有一个由各种子类(地址,医生,监护人等)组成的常驻课程。我对使accept_nested_attributes_for工作所需步骤的理解如下:
我的地址是为我的常驻记录工作的,但是当我尝试添加其他类时,我的挑战就出现了。例如,医生也需要一个地址,监护人也是如此。
我是否还会在我的doctor.rb模型中添加接受nested_attributes_for:地址?如果是这样,这是否意味着我需要一个控制器来为这个资源调用它的组件的构建方法?这是时候在我的表单模板中使用嵌套的fields_for了吗? (例子如下)
<%= f.fields_for :doc1 do |doc| %>
<%= doc.text_field :fname %>
<%= doc.text_field :lname %>
<%= doc.fields_for :address do |doc_address| %>
<%= doc_address.text_field :street_address %>
<%= doc_address.text_field :city %>
<%= doc_address.text_field :state %>
<% end %>
<%= doc.fields_for :primary_phone do |phone1| %>
<%= phone1.phone_field :area_code %>
<%= phone1.phone_field :number %>
<% end %>
<% end %>
以下是相关文件:
resident.rb
class Resident < ActiveRecord::Base
attr_accessible :address_attributes, :guardian_attributes, :desrep_attributes, :doctor_attributes,
:em_contact1_attributes, :em_contact2_attributes, :fname, :lname, :gender, :pic, :soc, :dob,
:marital_stat, :placement_name, :placement_address, :res_start_date,
:res_end_date, :religious_prefs, :insurance_info, :burial_provisions,
:case_number, :vet_stat_num, :admission_height, :admission_weight,
:resident_initials, :allergies,:admin_id
belongs_to :admin
has_one :address, as: :addressable
has_one :guardian
has_one :desrep, class_name: "DesignatedRepresentative"
has_one :doc1, class_name: "Doctor"
has_one :em_contact1, class_name: "EmergencyContact"
has_one :em_contact2, class_name: "EmergencyContact"
has_one :primary_phone, class_name: "PhoneNumber"
has_one :secondary_phone, class_name: "PhoneNumber"
has_many :assessment_plan_forms, dependent: :destroy
has_many :blood_pressure_record_forms, dependent: :destroy
has_many :fund_record_form1s, dependent: :destroy
has_many :fund_record_form2s, dependent: :destroy
has_many :incident_accident_forms, dependent: :destroy
has_many :med_record_forms, dependent: :destroy
has_many :personal_care_forms, dependent: :destroy
has_many :resident_care_agreement_forms, dependent: :destroy
has_many :visitation_appointment_forms, dependent: :destroy
has_many :weight_record_forms, dependent: :destroy
accepts_nested_attributes_for :address, allow_destroy: true
accepts_nested_attributes_for :guardian, allow_destroy: true
accepts_nested_attributes_for :desrep, allow_destroy: true
accepts_nested_attributes_for :doc1, allow_destroy: true
accepts_nested_attributes_for :em_contact1, allow_destroy: true
accepts_nested_attributes_for :em_contact2, allow_destroy: true
validates_presence_of :fname, :lname
def full_name
"#{ fname } #{ lname }"
end
def guard_fname
guarian.fname
end
end
address.rb
class Address < ActiveRecord::Base
attr_accessible :street_address, :city, :state, :zip, :addressable_type, :addressable_id
belongs_to :addressable, polymorphic: true
end
doctor.rb
class Address < ActiveRecord::Base
attr_accessible :street_address, :city, :state, :zip, :addressable_type, :addressable_id
belongs_to :addressable, polymorphic: true
end
emergency_contact.rb
class EmergencyContact < ActiveRecord::Base
attr_accessible :address_attributes, :primary_phone_attributes, :secondary_phone_attributes, :fax_attributes,
:fname, :lname, :primary, :email, :resident_id
belongs_to :resident
has_one :address, as: :addressable
has_one :primary_phone, class_name: "PhoneNumber"
has_one :secondary_phone, class_name: "PhoneNumber"
has_one :fax, as: :phoneable
accepts_nested_attributes_for :address
accepts_nested_attributes_for :primary_phone
accepts_nested_attributes_for :secondary_phone
accepts_nested_attributes_for :fax
end
resident_controller.rb - (构建代码在'new'方法内)
class ResidentsController < ApplicationController
before_filter :authenticate_admin!
def index
@residents = Resident.all
end
def new
@resident = Resident.new
@resident.build_address
@resident.build_guardian
@resident.build_desrep
@resident.build_em_contact1
@resident.build_em_contact2
end
end
views / resident / _form.html.erb (这显示了居民的工作地址fields_for)
<%= f.fields_for :address do |builder| %>
<div class="control-group">
<%= builder.label :street_address, "Address:", class: "control-label" %>
<div class="controls">
<%= builder.text_field :street_address, class: "text_field", placeholder: "Resident's Address" %>
</div>
</div>
<div class="control-group">
<%= builder.label :city, "City:", class: "control-label" %>
<div class="controls">
<%= builder.text_field :city, class: "text_field", placeholder: "Resident's City" %>
</div>
</div>
<div class="control-group">
<%= builder.label :state, "State:", class: "control-label" %>
<div class="controls">
<%= builder.text_field :state, class: "text_field", placeholder: "Resident's State" %>
</div>
</div>
<div class="control-group">
<%= builder.label :zip, "Zip:", class: "control-label" %>
<div class="controls">
<%= builder.text_field :zip, class: "text_field", placeholder: "Resident's Zip Code" %>
</div>
</div>
<% end %>
views / resident / _form.html.erb (这会将医生对象显示为'doc1',即无效)
<%= fields_for :doc1 do |doc| %>
<div class="control-group">
<%= doc.label :fname, "Doctor's First Name:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :fname, class: "text_field", placeholder: "Doctor's First Name" %>
</div>
</div>
<div class="control-group">
<%= doc.label :lname, "Doctor's Last Name:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :lname, class: "text_field", placeholder: "Doctor's Last Name" %>
</div>
</div>
<div class="control-group">
<%= doc.label :initials, "Initials:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :initials, class: "text_field", placeholder: "Doctor's Initials" %>
</div>
</div>
<div class="control-group">
<%= doc.label :phone1, "Doctor's Primary Phone:", class: "control-label" %>
<div class="controls">
<%= doc.phone_field :phone1_area_code, placeholder: "Area Code", style: "width: 25%;" %>
<%= doc.phone_field :phone1_number, class: "text_field", placeholder: "i.e. 800-555-1212" %>
</div>
</div>
<div class="control-group">
<%= doc.label :phone2, "Doctor's Secondary Phone:", class: "control-label" %>
<div class="controls">
<%= doc.phone_field :phone2_area_code, placeholder: "Area Code", style: "width: 25%;" %>
<%= doc.phone_field :phone2_number, class: "text_field", placeholder: "i.e. 800-555-1212" %>
</div>
</div>
<div class="control-group">
<%= doc.label :fax, "Doctor's Fax:", class: "control-label" %>
<div class="controls">
<%= doc.phone_field :fax_area_code, placeholder: "Area Code", style: "width: 25%;" %>
<%= doc.phone_field :fax_number, class: "text_field", placeholder: "Doctor's Fax Number" %>
</div>
</div>
<div class="control-group">
<%= doc.label :email, "Doctor's Email:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :email, class: "text_field", placeholder: "Doctor's Email Address" %>
</div>
</div>
<div class="control-group">
<%= doc.label :street_address, "Doctor's Address:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :street_address, class: "text_field", placeholder: "Doctor's Street Address" %>
</div>
</div>
<div class="control-group">
<%= doc.label :city, "Doctor's City:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :city, class: "text_field", placeholder: "Doctor's City" %>
</div>
</div>
<div class="control-group">
<%= doc.label :state, "Doctor's State:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :state, class: "text_field", placeholder: "Doctor's State" %>
</div>
</div>
<div class="control-group">
<%= doc.label :zip, "Doctor's Zip:", class: "control-label" %>
<div class="controls">
<%= doc.text_field :zip, class: "text_field", placeholder: "Doctor's Zip Code" %>
</div>
</div>
<% end %>
在使用accepts_nested_attributes之前,我想简单地延迟加载我的对象或通过初始化程序传递它们。但是我需要先做更多的阅读,因为到目前为止我无法使用这些技术得到我想要的结果。
我可以根据要求显示剩余的视图代码和任何其他文件。
提前致谢。
更新: 05-25-14 - 我仍在努力解决这个问题,并且已经写了this blog post关于我目前的理解情况。
答案 0 :(得分:7)
好的,要创建一个双(或两个以上)嵌套表单。以下是我为使事情发挥作用而采取的步骤。
class_name: "NameOfClass"
和/或inverse_of: :model_name
以消除Rails不必猜测)例如:
<强> teacher.rb 强>
class Teacher < ActiveRecord::Base
attr_accessible :first_name, :last_name, :address_attributes, :primary_phone_attributes, :secondary_phone_attributes,
:teacher_aids_attributes, :students_attributes
has_many :students, inverse_of: :teacher
has_many :teacher_aids, inverse_of: :teacher
has_one :address, as: :addressable, class_name: "Address"
has_one :email
has_one :primary_phone, as: :phoneable, class_name: "PhoneNumber"
has_one :secondary_phone, as: :phoneable, class_name: "PhoneNumber"
accepts_nested_attributes_for :address, :primary_phone, :secondary_phone, :teacher_aids, :students
end
<强> teacher_aid.rb 强>
class TeacherAid < ActiveRecord::Base
attr_accessible :first_name, :last_name, :address_attributes, :primary_phone_attributes, :secondary_phone_attributes, :teacher_id
belongs_to :teacher, inverse_of: :teacher_aids
has_many :students, inverse_of: :teacher_aids
has_one :address, as: :addressable, class_name: "Address"
has_one :email
has_one :primary_phone, as: :phoneable, class_name: "PhoneNumber"
has_one :secondary_phone, as: :phoneable, class_name: "PhoneNumber"
accepts_nested_attributes_for :address, :primary_phone, :secondary_phone
end
<强> student.rb 强>
class Student < ActiveRecord::Base
attr_accessible :first_name, :last_name, :address_attributes, :primary_phone_attributes, :secondary_phone_attributes,
:teacher_id, :teacher_aid_id
belongs_to :teacher
belongs_to :teacher_aid
has_one :address, as: :addressable, class_name: "Address"
has_one :email
has_one :primary_phone, as: :phoneable, class_name: "PhoneNumber"
has_one :secondary_phone, as: :phoneable, class_name: "PhoneNumber"
accepts_nested_attributes_for :address, :primary_phone, :secondary_phone
end
请注意我还在accepts_nested_attributes_for
和Student
类中添加了TeacherAid
。这是因为它们也由一个地址和两个phone_number对象组成。
attr_accessible
以白名单列出这些嵌套属性。例如:
老师有一个地址......
attr_accessible :teacher_first_name, :teacher_last_name, :address_attributes
老师有很多苹果......
attr_accessible :teacher_first_name, :teacher_last_name, :apples_attributes
请注意has_one
与has_many
的单数更改为复数拼写。
将accepts_nested_attribtues_for :name_of_nested_resource
添加到需要父表单模板上列出的组合对象的属性或属性的所有类中。
在父控制器(即您要用于存储所有组合对象的属性的控制器)中,在新方法中构建嵌套实例,如此。
例如:
<强> teachers_controller.rb 强>
class TeachersController < ApplicationController
def index
@teachers = Teacher.all
end
def new
@teacher = Teacher.new
@teacher.build_address
@teacher.build_primary_phone
@teacher.build_secondary_phone
@teacher_aid = @teacher.teacher_aids.build
@teacher_aid.build_address
@teacher_aid.build_primary_phone
@teacher_aid.build_secondary_phone
@student = @teacher.students.build
@student.build_address
@student.build_primary_phone
@student.build_secondary_phone
end
end
注意:我没有在我的后代类中创建任何构建方法,即使它们是由其他对象组成的。据我了解,这是由于Rails通过父级创建嵌套对象(即本例中为教师)。
以下是Rails指南中有关嵌套哈希的外观的示例:
例如:
<强> teacher_aids_controller.rb 强>
class TeacherAidsController < ApplicationController
before_filter :get_teacher_aid, except: [:index, :new, :create]
def index
@teacher_aids = TeacherAid.all
end
def new
@teacher_aids = TeacherAid.all
end
end
<强> students_controller.rb 强>
class StudentsController < ApplicationController
before_filter :get_student, except: [:index, :new, :create]
def index
@students = Student.all
end
def new
@student = Student.new
end
end
例如:
<强>教师/ _form.html.erb 强>
<%= form_for @teacher, html: { multipart: true, class: "form-horizontal" } do |f| %>
<%= f.text_field :first_name, placeholder: "Teacher's First Name" %><br />
<%= f.text_field :last_name, placeholder: "Teacher's Last Name" %><br />
<%= f.fields_for :address do |teacher_address| %>
<%= teacher_address.text_field :street_address, placeholder: "Teachers street_address" %>
<%= teacher_address.text_field :city, placeholder: "Teacher's city" %>
<%= teacher_address.text_field :state, placeholder: "Teacher's state" %>
<%= teacher_address.text_field :zip, placeholder: "Teacher's zip" %>
<% end %>
<%= f.fields_for :primary_phone do |teacher_phone1| %>
<%= teacher_phone1.phone_field :area_code, placeholder: "Primary Area Code" %>
<%= teacher_phone1.phone_field :number, placeholder: "Primary Number" %>
<% end %>
<%= f.fields_for :secondary_phone do |teacher_phone2| %>
<%= teacher_phone2.phone_field :area_code, placeholder: "Secondary Area Code" %>
<%= teacher_phone2.phone_field :number, placeholder: "Secondary Number" %>
<% end %>
<%= f.fields_for :teacher_aids do |teach_aid| %>
<%= teach_aid.text_field :first_name, placeholder: "Aid's First Name" %><br />
<%= teach_aid.text_field :last_name, placeholder: "Aid's Last Name" %><br />
<%= teach_aid.fields_for :address do |address| %>
<%= address.text_field :street_address, placeholder: "Aids Street Address" %><br />
<%= address.text_field :city, placeholder: "Aids city" %><br />
<%= address.text_field :state, placeholder: "Aids state" %><br />
<%= address.text_field :zip, placeholder: "Aids zip" %><br />
<%end %>
<%= teach_aid.fields_for :primary_phone do |phone1| %>
<%= phone1.phone_field :area_code, placeholder: "Aid's Area Code" %>
<%= phone1.phone_field :number, placeholder: "Aid's Primary Number" %>
<% end %>
<%= teach_aid.fields_for :secondary_phone do |phone2| %>
<%= phone2.phone_field :area_code, placeholder: "Aid's Area Code" %>
<%= phone2.phone_field :number, placeholder: "Aid's Secondary Number" %>
<% end %>
<% end %>
注意:address,:primary_phone和:secondary_phone都嵌套在各自的fields_for下,用于各自的对象。
我目前的障碍是现在我的primary_phone和secondary_phone多态模型只显示主要手机数据。这意味着由于某种原因,has_one :primary_phone, as: :phoneable, class_name: "PhoneNumber"
和has_one :secondary_phone, as: :phoneable, class_name: "PhoneNumber"
并不被视为两个独立的事物。但这是另一个问题的主题。