Reputation: 105
Example from Guide with additional property in association model
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
Model Appointment has a validation:
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
When I add patient to physicians some_physician.patient << some_patient
I have to define appointment_date
. How to do it correctly?
Upvotes: 1
Views: 344
Reputation: 17812
How to do it correctly?
In my opinion, you can define a method, and pass that method into before_save
callback.
class Appointment < ActiveRecord::Base
before_save :set_appointment_date
private
def set_appointment_date
self.appointment_date = Time.now
end
end
That's how you don't need to explicitly set the appointment_date
each time you create a relationship. It will be automatically set for you.
Edit:
before_save
will also fire if you later want to update
your appointment object, though that is a very rare case. But it will update the appointment_date
. For that, you can use before_create
callback, and appointment_date
will be touched only once in that case.
Upvotes: 3
Reputation: 44380
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.
Upvotes: 2
Reputation: 4956
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)
Upvotes: 2