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
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.
before_destroy callback before the
dependent: :destroy association
class Course < ApplicationRecord before_destroy :notify_members has_many :course_members, dependent: :destroy end
prepend: true option
class Course < ApplicationRecord has_many :course_members, dependent: :destroy before_destroy :notify_members, prepend: true end
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.
This documentation is beautifully and clearly written and you will find all what you need regarding callbacks thoroughly explained.