我有一个由各种儿童班(地址,医生,监护人等)组成的居民班.我对使accept_nested_attributes_for工作所需步骤的理解如下:
>创建必要的关联
>将accepts_nested_attributes_for:resource添加到父类,其形式我将用于提交嵌套属性
>白名单嵌套属性就像这样. attr_accessible:address_attributes,:doctor_attributes等…
>在父控制器中,构建关联的资源.即@ resident.addresses.build(用于has_many关联),@ resident.build_doctor(用于has_one关联)
>为每个子资源添加fields_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关于我目前在理解的地方.
好的,要创建一个双(或两个以上)嵌套表单.以下是我为使事情发挥作用而采取的步骤.>定义正确的关联(记得添加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
请注意我如何在Student和TeacherAid类中添加accepts_nested_attributes_for.这是因为它们也由一个地址和两个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 vs 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
>当添加双重(或多于两个)嵌套:address_attributes或任何名称时,我们需要在视图模板中嵌套fields_for,如此.
例如:
教师/ _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,如:: phoneable,class_name:“PhoneNumber”和has_one:secondary_phone,如::phoneable,class_name:“PhoneNumber”不被视为两个单独的东西.但这是另一个问题的主题.