Specify callbacks before specifying the associations
Just wasted a full day on this… Suppose you have a User model, with certain Users being children and other Users being parents. With the following code I intended to delete the parent when the child being deleted is the last child of the parent:
class ChildParent < ActiveRecord::Base
belongs_to :child, :class_name => "User"
belongs_to :parent, :class_name => "User"
end
class User < ActiveRecord::Base
has_many :parents, :through => :child_parents_as_child
has_many :child_parents_as_child, :foreign_key => :child_id, :class_name => "ChildParent", :dependent => :destroy
has_many :children, :through => :child_parents_as_parent
has_many :child_parents_as_parent, :foreign_key => :parent_id, :class_name => "ChildParent", :dependent => :destroy
before_destroy :determine_parents_to_be_destroyed
after_destroy :destroy_parents
private
def determine_parents_to_be_destroyed
@destroy_parents = []
self.parents.each do |p|
@destroy_parents << p unless p.children.size > 1
end
end
def destroy_parents
@destroy_parents.each do |p|
p.destroy
end
end
end
This didn’t work – @destroy_parents was never populated. Finally I stumbled on the following sentence, clearly documented in the api for ActiveRecord, yet easily missed: *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the callbacks before specifying the associations. Otherwise, you might trigger the loading of a child before the parent has registered the callbacks and they won‘t be inherited.
Moving the before_destroy and after_destroy declarations above the associations solved the problem.
leave a comment