Rails has_many :through 嵌套表单

28

我刚刚开始了解has_many :through关联。我正在尝试通过单个表格实现保存所有三个表格(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 %>

我能创建一个新的患者,医生和关联记录以进行约会,但现在我想在表单中加入预约日期字段。我应该在哪里放置预约的字段,并且我的控制器需要做出什么改变?我尝试了谷歌和尝试这个,但在实施过程中卡住了。

1
另一个提示:您可以使用 t.references: patient,而不是 t.integer: patient_id 来创建适当类型的列。请参阅http://guides.rubyonrails.org/migrations.html#special-helpers。 - Robin
3个回答

30

好的,这个小问题让我困惑了几个小时,所以我将我的解决方案发布在这里,希望能为大家节省一些时间。这适用于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 Physician < ActiveRecord::Base
  has_many :appointments
  has_many :patients, through: :appointments
end

控制器:

# patients_controller.rb
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 %>

哦,谢谢您!这个问题也让我忙了好一段时间。 - Max
2
你难道不需要对医生的名称属性进行 strong-param-permit 处理吗? - Felix

7
“我已经让它正常工作了。我只是按照以下方式更改了模型”:摘自上面评论中的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

4
你的patient类接受医生和预约的嵌套属性。尝试为预约添加另一个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 快速回复。我尝试了这段代码,结果在预约表中插入了两条记录:第一条记录保存了病人ID和预约日期,第二条记录保存了医生ID和病人ID。控制器或模型需要做出任何更改吗? - S R
@kien 如果我这样做,appointment_date文本框就不会在我的表单上显示 :( - S R
实际上我非常困惑何时应该使用accepts_nested_attributes_for。我已经修改了我的Patient模型,现在它看起来像这样:class Patient < ActiveRecord::Base has_many :appointments has_many :physicians, :through => :appointments # accepts_nested_attributes_for :appointments accepts_nested_attributes_for :physicians end - S R
3
我搞定了,只是按照以下方式更改了模型: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 - S R
3
我正在处理一个类似的情况,但我一直遇到错误。您是否可以发布最终的、可运行的代码?可以作为答案吗?我猜这将不仅对我有帮助,也会对其他遇到同样问题的人有所帮助。 - nullnullnull
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接