diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index dab5a502a51f06522401706184c03e37def7912b..9046fe3e30685635922d9d56ce194fcd337c385d 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -694,7 +694,7 @@ def through_reflection def chain @chain ||= begin a = source_reflection.chain - b = through_reflection.chain + b = through_reflection.chain.map(&:dup) if options[:source_type] b[0] = PolymorphicReflection.new(b[0], self) diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 67e9bef808aea529126fa4c221a83f14629c0dce..9893fbd6b92eb198a5c4d07b2dcf878bba364d39 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -23,6 +23,7 @@ require 'models/department' require 'models/cake_designer' require 'models/drink_designer' +require 'models/recipe' class ReflectionTest < ActiveRecord::TestCase include ActiveRecord::Reflection @@ -277,6 +278,16 @@ def test_scope_chain_does_not_interfere_with_hmt_with_polymorphic_case assert_equal 2, @hotel.chefs.size end + def test_scope_chain_of_polymorphic_association_does_not_leak_into_other_hmt_associations + hotel = Hotel.create! + department = hotel.departments.create! + drink = department.chefs.create!(employable: DrinkDesigner.create!) + recipe = Recipe.create!(chef_id: drink.id, hotel_id: hotel.id) + + hotel.drink_designers.to_a + assert_sql(/^(?!.*employable_type).*$/) { hotel.recipes.to_a } + end + def test_nested? assert !Author.reflect_on_association(:comments).nested? assert Author.reflect_on_association(:tags).nested? diff --git a/activerecord/test/models/chef.rb b/activerecord/test/models/chef.rb index 67a4e54f061b20af72df8825a33a9bb12c6e4157..698a52e045d93a7cad590dd09f7ac92e4b8333e2 100644 --- a/activerecord/test/models/chef.rb +++ b/activerecord/test/models/chef.rb @@ -1,3 +1,4 @@ class Chef < ActiveRecord::Base belongs_to :employable, polymorphic: true + has_many :recipes end diff --git a/activerecord/test/models/hotel.rb b/activerecord/test/models/hotel.rb index b352cd22f32373f64409a36c68a4829d335adcf7..491f8dfde3c6f7c6b2d2c81586ff0cc6e1772bb5 100644 --- a/activerecord/test/models/hotel.rb +++ b/activerecord/test/models/hotel.rb @@ -3,4 +3,5 @@ class Hotel < ActiveRecord::Base has_many :chefs, through: :departments has_many :cake_designers, source_type: 'CakeDesigner', source: :employable, through: :chefs has_many :drink_designers, source_type: 'DrinkDesigner', source: :employable, through: :chefs + has_many :recipes, through: :chefs end diff --git a/activerecord/test/models/recipe.rb b/activerecord/test/models/recipe.rb new file mode 100644 index 0000000000000000000000000000000000000000..c3872306035c2eebba6117250952ca7965714e21 --- /dev/null +++ b/activerecord/test/models/recipe.rb @@ -0,0 +1,3 @@ +class Recipe < ActiveRecord::Base + belongs_to :chef +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 5e5f7a798ec19619c8966124e43a1d3b8bdb7985..7b42f8a4a5b8ce7b9041d68a213feb0f296d3180 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -886,6 +886,10 @@ def except(adapter_names_to_exclude) t.string :employable_type t.integer :department_id end + create_table :recipes, force: true do |t| + t.integer :chef_id + t.integer :hotel_id + end create_table :records, force: true do |t| end