aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorRyuta Kamizono <kamipo@gmail.com>2017-10-30 23:55:48 +0900
committerRyuta Kamizono <kamipo@gmail.com>2017-11-06 05:52:52 +0900
commite617fb57f5a388d5f0a47fd5e576588dd10066b0 (patch)
tree4225fe0bfa8bb3680852c624d42f0bcca522a831 /activerecord
parent8a2ee3d8c6921ce34e597658e3f2b43b41423d1d (diff)
downloadrails-e617fb57f5a388d5f0a47fd5e576588dd10066b0.tar.gz
rails-e617fb57f5a388d5f0a47fd5e576588dd10066b0.tar.bz2
rails-e617fb57f5a388d5f0a47fd5e576588dd10066b0.zip
Fix preloading polymorphic association when through association has already loaded
If through association has already loaded, `source_type` is ignored to loaded through records. The loaded records should be filtered by `source_type` in that case. Fixes #30904.
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb20
-rw-r--r--activerecord/test/cases/associations/nested_through_associations_test.rb11
2 files changed, 27 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index fa32cc5553..5bd49b041a 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -13,18 +13,30 @@ module ActiveRecord
end
def associated_records_by_owner(preloader)
+ already_loaded = owners.first.association(through_reflection.name).loaded?
through_scope = through_scope()
- preloader.preload(owners,
- through_reflection.name,
- through_scope)
+ unless already_loaded
+ preloader.preload(owners, through_reflection.name, through_scope)
+ end
through_records = owners.map do |owner|
center = owner.association(through_reflection.name).target
[owner, Array(center)]
end
- reset_association(owners, through_reflection.name, through_scope)
+ if already_loaded
+ if source_type = reflection.options[:source_type]
+ through_records.map! do |owner, center|
+ center = center.select do |record|
+ record[reflection.foreign_type] == source_type
+ end
+ [owner, center]
+ end
+ end
+ else
+ reset_association(owners, through_reflection.name, through_scope)
+ end
middle_records = through_records.flat_map(&:last)
diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb
index 4cf5a9ffc4..11ee45917f 100644
--- a/activerecord/test/cases/associations/nested_through_associations_test.rb
+++ b/activerecord/test/cases/associations/nested_through_associations_test.rb
@@ -579,6 +579,17 @@ class NestedThroughAssociationsTest < ActiveRecord::TestCase
assert !c.post_taggings.empty?
end
+ def test_polymorphic_has_many_through_when_through_association_has_already_loaded
+ cake_designer = CakeDesigner.create!(chef: Chef.new)
+ drink_designer = DrinkDesigner.create!(chef: Chef.new)
+ department = Department.create!(chefs: [cake_designer.chef, drink_designer.chef])
+ Hotel.create!(departments: [department])
+ hotel = Hotel.includes(:chefs, :cake_designers, :drink_designers).take
+
+ assert_equal [cake_designer], hotel.cake_designers
+ assert_equal [drink_designer], hotel.drink_designers
+ end
+
def test_polymorphic_has_many_through_joined_different_table_twice
cake_designer = CakeDesigner.create!(chef: Chef.new)
drink_designer = DrinkDesigner.create!(chef: Chef.new)