Rails has_many:通过嵌套形式

Posted

技术标签:

【中文标题】Rails has_many:通过嵌套形式【英文标题】:Rails has_many :through nested form 【发布时间】:2012-11-10 11:59:16 【问题描述】:

我刚刚加入has_many :through 协会。我正在尝试通过一个表单实现为所有 3 个表(PhysicianPatient 和关联表)保存数据的能力。

我的迁移:

class CreatePhysicians < ActiveRecord::Migration
  def self.up
    create_table :physicians do |t|
      t.string :name
      t.timestamps
    end
  end
end

class CreatePatients < ActiveRecord::Migration
  def self.up
    create_table :patients do |t|
      t.string :name
      t.timestamps
    end
  end
end

class CreateAppointments < ActiveRecord::Migration
  def self.up
    create_table :appointments do |t|
      t.integer :physician_id
      t.integer :patient_id
      t.date :appointment_date
      t.timestamps
    end
  end
end

我的模型:

class Patient < ActiveRecord::Base
  has_many :appointments
  has_many :physicians, :through => :appointments
  accepts_nested_attributes_for :appointments
  accepts_nested_attributes_for :physicians
end
class Physician < ActiveRecord::Base
  has_many :appointments
  has_many :patients, :through => :appointments
  accepts_nested_attributes_for :patients
  accepts_nested_attributes_for :appointments
end
class Appointment < ActiveRecord::Base
  belongs_to :physician
  belongs_to :patient
end

我的控制器:

def new
    @patient = Patient.new
    @patient.physicians.build
    @patient.appointments.build
end

我的看法(new.html.rb):

<% form_for(@patient) do |patient_form| %>
  <%= patient_form.error_messages %>
  <p>
    <%= patient_form.label :name, "Patient Name" %>
    <%= patient_form.text_field :name %>
  </p>
  <%  patient_form.fields_for :physicians do |physician_form| %>
    <p>
      <%= physician_form.label :name, "Physician Name" %>
      <%= physician_form.text_field :name %>
    </p>
 <% end %>

  <p>
    <%= patient_form.submit 'Create' %>
  </p>
<% end %>

<%= link_to 'Back', patients_path %>

我可以为Appointment 创建一个新的PatientPhysician 和关联记录,但现在我也想在表单中为appointment_date 提供字段。我应该在哪里放置Appointments 的字段以及我的控制器需要进行哪些更改?我尝试了谷歌搜索并尝试了this,但在实现它时遇到了一些或其他错误。

【问题讨论】:

另一个提示:您可以使用t.references :patient 而不是t.integer :patient_id 来创建适当类型的列。见guides.rubyonrails.org/migrations.html#special-helpers 【参考方案1】:

好的,这个问题的小问题困扰了我几个小时,所以我将在这里发布我的工作解决方案,希望它可以节省一些时间进行窥视。这适用于 Rails 4.0 和 Ruby 2.0。这也克服了我遇到的“符号到整数转换”的问题。

型号:

class Patient < ActiveRecord::Base 
  has_many :appointments
  has_many :physicians, :through: :appointments
  accepts_nested_attributes_for :appointments
end 

class Appointment < ActiveRecord::Base
  belongs_to :physician 
  belongs_to :patient
  accepts_nested_attributes_for :physician
end

class Physicians < ActiveRecord::Base
  has_many :appointments
  has_many :patients, through: :appointments
end

控制器:

def new
  @patient= Patient.new 
  @appointments = @patient.appointments.build
  @physician = @appointments.build_physician 
end

def create
  Patient.new(patient_params)
end


def patient_params
   params.require(:patient).permit(:id, appointments_attributes: [:id, :appointment_time, physician_attributes: [:id ] )
end

查看

<% form_for(@patient) do |patient_form| %>
  <%= patient_form.error_messages %>
  <p>
    <%= patient_form.label :name, "Patient Name" %>
    <%= patient_form.text_field :name %>
  </p>

  <% patient_form.fields_for :appointments do |appointment_form| %>
    <p>
      <%= appointment_form.label :appointment_date, "Appointment Date" %>
      <%= appointment_form.date_field :appointment_date %>
    </p>

    <% appointment_form.fields_for :physician do |physician_form| %>
      <p>
        <%= physician_form.label :name, "Physician Name" %>
        <%= physician_form.text_field :name %>
      </p>
    <% end %>
  <% end %>

  <p>
    <%= patient_form.submit 'Create' %>
  </p>
<% end %>

<%= link_to 'Back', patients_path %>

【讨论】:

哦,谢谢!这个混蛋也让我忙了好一阵子。 难道医生的姓名属性也需要strong-param-permit吗?【参考方案2】:

“我得到了它的工作。我只是改变了模型如下”:引用来自上面 cmets 中的 Shruti

class Patient < ActiveRecord::Base 
  has_many :appointments, :dependent => :destroy 
  has_many :physicians, :through => :appointments
  accepts_nested_attributes_for :appointments
end 

class Appointment < ActiveRecord::Base
  belongs_to :physician 
  belongs_to :patient
  accepts_nested_attributes_for :physician
end

【讨论】:

【参考方案3】:

您的患者类接受医生和预约的嵌套属性。尝试添加另一个fields_for 预约方法。

<% form_for(@patient) do |patient_form| %>
  <%= patient_form.error_messages %>
  <p>
    <%= patient_form.label :name, "Patient Name" %>
    <%= patient_form.text_field :name %>
  </p>

  <% patient_form.fields_for :physicians do |physician_form| %>
    <p>
      <%= physician_form.label :name, "Physician Name" %>
      <%= physician_form.text_field :name %>
    </p>
  <% end %>

  <% patient_form.fields_for :appointments do |appointment_form| %>
    <p>
      <%= appointment_form.label :appointment_date, "Appointment Date" %>
      <%= appointment_form.date_field :appointment_date %>
    </p>
  <% end %>

  <p>
    <%= patient_form.submit 'Create' %>
  </p>
<% end %>

<%= link_to 'Back', patients_path %>

【讨论】:

感谢@andrew 的快速回复。我尝试了代码,它导致 2 条记录被插入到约会表中:在第一条记录中,patent_id 和约会日期被保存,在第二条记录中,医生 ID 和病人 ID 被保存。需要对控制器或模型进行任何更改吗? @Shruti 我认为您应该删除@patient.appointments.build,并在您的创建操作中使用@patient.save 来保存对象。 @kien 如果我这样做,约会日期文本字段在我的表单上不可见:( 我搞定了。我只是将模型更改如下:class Patient &lt; ActiveRecord::Base has_many :appointments, :dependent =&gt; :destroy has_many :physicians, :through =&gt; :appointments accepts_nested_attributes_for :appointments end class Appointment &lt; ActiveRecord::Base belongs_to :physician belongs_to :patient accepts_nested_attributes_for :physician end 我正在处理类似的情况,但我一直遇到错误。您可以发布最终的工作代码吗?也许作为答案?我怀疑它不仅会帮助我,还会帮助处理同样问题的其他人。

以上是关于Rails has_many:通过嵌套形式的主要内容,如果未能解决你的问题,请参考以下文章

Rails has_many,如何实现嵌套关联?

使用带有 Rails 的改革 gem,我如何填充 has_many :通过嵌套模型

带有has_many的Rails嵌套表单:通过,如何编辑连接模型的属性?

Rails:如何通过 has_many 进行优雅的调用

has_many的Rails组合框问题:通过关系

Rails:为啥“has_many ...,:通过=> ...”关联导致“NameError:未初始化的常量...”