DEV Community

loading...
Cover image for Using before_destroy callback to do some association logic

Using before_destroy callback to do some association logic

yasmine_khalil profile image Yasmine Medhat ・2 min read

Have you ever had the task to do some external logic on the model association on destroying a record?

Luckily, we did. After destroying a course, all users registered to that course should be notified and we are notifying the users in a background job using Sidekiq.

Well, we might all think (or at least that's what we did, you might have read the docs. thoroughly :D) that it is straightforward, use a before_destory callback, notify the users then destroy the course.

Not so fast. What we noticed is that whenever we tried to find the registered users, we could not find neither the users nor the course.

Turns out the before_destroy callback is run after the record is deleted (but still not committed to the DB). Since callbacks are run in order, with the dependent: :destroy the associated records are deleted before the record is deleted. Thus, all of that is done before the before_destroy callbacks are called.

Our model looked something like this:

class Course < ApplicationRecord
  has_many :course_members, dependent: :destroy
  before_destroy :notify_members
end
Enter fullscreen mode Exit fullscreen mode

where notify_members take the user ids as parameters.

Okay you might be thinking okay stranger we get it just get straight to the solution, so here it is. There is actually two easy solutions mentioned in the docs.

Sol. 1

Place the before_destroy callback before the dependent: :destroy association

class Course < ApplicationRecord
  before_destroy :notify_members
  has_many :course_members, dependent: :destroy
end
Enter fullscreen mode Exit fullscreen mode

Sol. 2

Use the prepend: true option

class Course < ApplicationRecord
  has_many :course_members, dependent: :destroy
  before_destroy :notify_members, prepend: true
end
Enter fullscreen mode Exit fullscreen mode

When the prepend option is set to true, our callback is going to be prepended to the callbacks chain rather than appended.

I like to use the second solution better. However, either way your before_destory callback now is going to find the associated records safe and sound.

Lastly, You might keep in mind that you might face a problem if an exception was raised and the deletion was actually rolled back since the before_destroy is called before committing to the DB.

Reference: active_record_callbacks
This documentation is beautifully and clearly written and you will find all what you need regarding callbacks thoroughly explained.

Discussion (0)

Forem Open with the Forem app