From 88f951a519d750236cc157566ef10f3977c933e1 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 27 Oct 2007 20:31:09 +0000 Subject: [PATCH] Allow association redefinition in subclasses. Closes #9346. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8046 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/CHANGELOG | 2 + .../lib/active_record/associations.rb | 6 +- activerecord/test/aggregations_test.rb | 18 +++++ activerecord/test/associations_test.rb | 65 +++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 6847755e6e..1875eda3ba 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Allow association redefinition in subclasses. #9346 [wildchild] + * Fix has_many :through delete with custom foreign keys. #6466 [naffis] * Foxy fixtures, from rathole (http://svn.geeksomnia.com/rathole/trunk/README) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index e542e8d85a..654b24d71c 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -955,7 +955,7 @@ module ActiveRecord # Don't use a before_destroy callback since users' before_destroy # callbacks will be executed after the association is wiped out. old_method = "destroy_without_habtm_shim_for_#{reflection.name}" - class_eval <<-end_eval + class_eval <<-end_eval unless method_defined?(old_method) alias_method :#{old_method}, :destroy_without_callbacks def destroy_without_callbacks #{reflection.name}.clear @@ -1351,7 +1351,9 @@ module ActiveRecord defined_callbacks = options[callback_name.to_sym] if options.has_key?(callback_name.to_sym) class_inheritable_reader full_callback_name.to_sym - write_inheritable_array(full_callback_name.to_sym, [defined_callbacks].flatten) + write_inheritable_attribute(full_callback_name.to_sym, [defined_callbacks].flatten) + else + write_inheritable_attribute(full_callback_name.to_sym, []) end end end diff --git a/activerecord/test/aggregations_test.rb b/activerecord/test/aggregations_test.rb index 89927e5044..299e0484e3 100644 --- a/activerecord/test/aggregations_test.rb +++ b/activerecord/test/aggregations_test.rb @@ -108,3 +108,21 @@ class AggregationsTest < Test::Unit::TestCase assert_equal nil, customers(:david).gps_location end end + +class OverridingAggregationsTest < Test::Unit::TestCase + class Name; end + class DifferentName; end + + class Person < ActiveRecord::Base + composed_of :composed_of, :mapping => %w(person_first_name first_name) + end + + class DifferentPerson < Person + composed_of :composed_of, :class_name => 'DifferentName', :mapping => %w(different_person_first_name first_name) + end + + def test_composed_of_aggregation_redefinition_reflections_should_differ_and_not_inherited + assert_not_equal Person.reflect_on_aggregation(:composed_of), + DifferentPerson.reflect_on_aggregation(:composed_of) + end +end diff --git a/activerecord/test/associations_test.rb b/activerecord/test/associations_test.rb index 121a8c5ac4..1fe8d2a417 100755 --- a/activerecord/test/associations_test.rb +++ b/activerecord/test/associations_test.rb @@ -1932,3 +1932,68 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase end end end + + +class OverridingAssociationsTest < Test::Unit::TestCase + class Person < ActiveRecord::Base; end + class DifferentPerson < ActiveRecord::Base; end + + class PeopleList < ActiveRecord::Base + has_and_belongs_to_many :has_and_belongs_to_many, :before_add => :enlist + has_many :has_many, :before_add => :enlist + belongs_to :belongs_to + has_one :has_one + end + + class DifferentPeopleList < PeopleList + # Different association with the same name, callbacks should be omitted here. + has_and_belongs_to_many :has_and_belongs_to_many, :class_name => 'DifferentPerson' + has_many :has_many, :class_name => 'DifferentPerson' + belongs_to :belongs_to, :class_name => 'DifferentPerson' + has_one :has_one, :class_name => 'DifferentPerson' + end + + def test_habtm_association_redefinition_callbacks_should_differ_and_not_inherited + # redeclared association on AR descendant should not inherit callbacks from superclass + callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) + assert_equal([:enlist], callbacks) + callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_and_belongs_to_many) + assert_equal([], callbacks) + end + + def test_has_many_association_redefinition_callbacks_should_differ_and_not_inherited + # redeclared association on AR descendant should not inherit callbacks from superclass + callbacks = PeopleList.read_inheritable_attribute(:before_add_for_has_many) + assert_equal([:enlist], callbacks) + callbacks = DifferentPeopleList.read_inheritable_attribute(:before_add_for_has_many) + assert_equal([], callbacks) + end + + def test_habtm_association_redefinition_reflections_should_differ_and_not_inherited + assert_not_equal( + PeopleList.reflect_on_association(:has_and_belongs_to_many), + DifferentPeopleList.reflect_on_association(:has_and_belongs_to_many) + ) + end + + def test_has_many_association_redefinition_reflections_should_differ_and_not_inherited + assert_not_equal( + PeopleList.reflect_on_association(:has_many), + DifferentPeopleList.reflect_on_association(:has_many) + ) + end + + def test_belongs_to_association_redefinition_reflections_should_differ_and_not_inherited + assert_not_equal( + PeopleList.reflect_on_association(:belongs_to), + DifferentPeopleList.reflect_on_association(:belongs_to) + ) + end + + def test_has_one_association_redefinition_reflections_should_differ_and_not_inherited + assert_not_equal( + PeopleList.reflect_on_association(:has_one), + DifferentPeopleList.reflect_on_association(:has_one) + ) + end +end