has_many:通过协会

时间:2015-06-30 12:57:28

标签: ruby-on-rails activerecord

指南中的示例以及关联模型中的附加属性

class CreateAppointments < ActiveRecord::Migration
  def change
    create_table :physicians do |t|
      t.string :name
      t.timestamps null: false
    end

    create_table :patients do |t|
      t.string :name
      t.timestamps null: false
    end

    create_table :appointments do |t|
      t.belongs_to :physician, index: true
      t.belongs_to :patient, index: true
      t.datetime :appointment_date
      t.timestamps null: false
    end
  end
end

模型约会有一个验证:

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

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

  validates :appointment_date, presence: true
end

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

当我向患者some_physician.patient << some_patient添加患者时,我必须定义appointment_date。如何正确地做到这一点?

3 个答案:

答案 0 :(得分:3)

  

如何正确地做到这一点?

在我看来,您可以定义一个方法,并将该方法传递给before_save回调。

class Appointment < ActiveRecord::Base
  before_save :set_appointment_date

  private
  def set_appointment_date
    self.appointment_date = Time.now
  end
end

每次创建关系时,您都不需要明确设置appointment_date。它会自动为您设置。

修改 如果您以后想要before_save约会对象,update也会触发,尽管这是一种非常罕见的情况。但它会更新appointment_date。为此,您可以使用before_create回调,在这种情况下,只会触摸appointment_date一次。

答案 1 :(得分:2)

The reason you have to define it is because some_physician.patient << some_patient creates an implicit appointment to link the two. An appointment is invalid if you leave appointment_date blank.

If you don't want an appointment, define a new relationship between physicians and patients.

Otherwise it makes sense to do something like:

appointment = some_physician.appointments.create(patient: some_patient, appointment_date: Time.now)

答案 2 :(得分:2)

It is can be achieved without before_save callback, Rails update timestamps automatically. Just create a right migration file, assume you are use postgresql as orm.

create_table :appointments do |t|
  t.belongs_to :physician, index: true
  t.belongs_to :patient, index: true
  t.timestamps :appointment_date, default: 'now()'
  t.timestamps null: false
end

Instead datetime columntype use timestamps as created_at or updated_at with a plain sql function now()

Current date and time (equivalent to current_timestamp)

It's happens under the hood.

Some references