Andrey Skuratovsky
Andrey Skuratovsky

Reputation: 687

Rails 4 association validate destroy

I have two models with many-to-many association through third model. By ex:

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

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

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

And using simple_form i have this checkbox set (Physician form):

...
= f.association :patients, as: :check_boxes
...

When i check some checkboxes, after save rails will create appointments in database.

When i uncheck checkboxes, rails will destroy some unchecked appointments.

So update will be eq to

physician.patient_ids = []

I want to validate appointments before delete. By example if appointments have some warnings, i want to show alert validation error on saving Physician form.

So, i thought, maybe rails will call destroy method on appointments, and tried:

class Appointment < ActiveRecord::Base

before_destroy :check_destroy
private
def check_destroy
  raise 'you can not do it!'
end

Nope, rails just removed appointments from database on save Physician.

Maybe rails will use delete method? Then i tried this one:

  class Appointment < ActiveRecord::Base
  def delete
    raise 'you can not do it!'
  end

Nope, again.

Seems to rails just remove join-association (appointment) straight from database.

How to prevent it? I want to validate all appointments that will be deleted before saving Physician, and add error to Physician if some appointments can not be deleted.

Upvotes: 2

Views: 1418

Answers (1)

pshoukry
pshoukry

Reputation: 765

From the rails documentation

Similar to the normal callbacks that hook into the life cycle of an Active Record object, you can also define callbacks that get triggered when you add an object to or remove an object from an association collection.

Example from Docs

class Project
  has_and_belongs_to_many :developers, after_add: :evaluate_velocity

  def evaluate_velocity(developer)
    ...
  end
end

So in your particular scenario try

  has_many :patients, through: :appointments, before_remove :check_remove

Upvotes: 4

Related Questions