In the case of a has_many :through relationship, which also
happens to be polymorphic in both directions, the after_add
callback gets executed for both the direct relationship and the
through relationship. It seems like there is an inconsistency
though, as the after_remove callback only gets executed on the
direct relationship and not the through relationship. This is best
shown by the following example where there are polymorphic types
Locations and People. User being and instance of Person and Address
being an instance of Location.
# location_person.rb
class LocationPerson < ActiveRecord::Base
belongs_to :location, :polymorphic => true
belongs_to :person, :polymorphic => true
end
# address.rb
class Address < ActiveRecord::Base
has_many :people, :as => :location, :class_name => "LocationPerson"
end
# user.rb
class User < ActiveRecord::Base
has_many :locations, :as => :person, :class_name => "LocationPerson", :after_remove => :remove_location_point, :after_add => :add_location_point
has_many :addresses, :through => :locations, :source => :location, :source_type => "Address", :after_remove => :remove_address_point, :after_add => :add_address_point
def remove_location_point(location)
puts "Removing Location Point"
end
def remove_address_point(address)
puts "Removing Address Point"
end
def add_location_point(location)
puts "Adding Location Point"
end
def add_address_point(address)
puts "Adding Address Point"
end
end
Call the following in console to demonstrate the asymetry:
ruby-1.8.7-p302 > user = User.create
=> #<User id: 2, created_at: "2010-12-22 15:44:14", updated_at: "2010-12-22 15:44:14">
ruby-1.8.7-p302 > addr = Address.create
=> #<Address id: 2, created_at: "2010-12-22 15:44:23", updated_at: "2010-12-22 15:44:23">
ruby-1.8.7-p302 > user.addresses << addr
Adding Location Point
Adding Address Point
=> [#<Address id: 2, created_at: "2010-12-22 15:44:23", updated_at: "2010-12-22 15:44:23">]
ruby-1.8.7-p302 > user.addresses = []
Removing Address Point
=> []
As you can see, "Adding Location Point" and "Adding Address
Point" were both printed indicating both after_add callbacks were
executed. However only "Removing Address Point" was printed
indicating that the after_remove callback on the :locations
relationship was never called.