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.
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
Sol. 2
Use the 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.
Reference: active_record_callbacks
This documentation is beautifully and clearly written and you will find all what you need regarding callbacks thoroughly explained.
Top comments (0)