Rob van Dijk's Blog

Specify callbacks before specifying the associations

Posted in rubyonrails by Rob van Dijk on 05/02/2010

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.

About these ads

Geef een reactie

Vul je gegevens in of klik op een icoon om in te loggen.

WordPress.com logo

Je reageert onder je WordPress.com account. Log uit / Bijwerken )

Twitter-afbeelding

Je reageert onder je Twitter account. Log uit / Bijwerken )

Facebook foto

Je reageert onder je Facebook account. Log uit / Bijwerken )

Google+ photo

Je reageert onder je Google+ account. Log uit / Bijwerken )

Verbinden met %s

Volg

Ontvang elk nieuw bericht direct in je inbox.

%d bloggers like this: