aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
authorEileen M. Uchitelle <eileencodes@users.noreply.github.com>2018-10-04 11:03:24 -0400
committerGitHub <noreply@github.com>2018-10-04 11:03:24 -0400
commitddac80a951beb307d5d7adb781f6dd1d1f169f7e (patch)
treee35255c49833c6cb4b15d3774acb76f98c33d8f5 /activerecord/lib/active_record
parent414c70e072466ebe40e7c46795f27c48cba8d717 (diff)
parentd634c0d82b8ebd7b019baed535d89541bc8e4f6a (diff)
downloadrails-ddac80a951beb307d5d7adb781f6dd1d1f169f7e.tar.gz
rails-ddac80a951beb307d5d7adb781f6dd1d1f169f7e.tar.bz2
rails-ddac80a951beb307d5d7adb781f6dd1d1f169f7e.zip
Merge pull request #33938 from faucct/bugfix/preload_through_no_records
ActiveRecord::Associations::Preloader should not fail to preload through missing records
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb52
1 files changed, 24 insertions, 28 deletions
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index a8f94b574d..9253f4ccb4 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -98,12 +98,14 @@ module ActiveRecord
# Loads all the given data into +records+ for the +association+.
def preloaders_on(association, records, scope, polymorphic_parent = false)
- if association.respond_to?(:to_hash)
+ case association
+ when Hash
preloaders_for_hash(association, records, scope, polymorphic_parent)
- elsif association.is_a?(Symbol)
- preloaders_for_one(association, records, scope, polymorphic_parent)
- elsif association.respond_to?(:to_str)
- preloaders_for_one(association.to_sym, records, scope, polymorphic_parent)
+ when Symbol, String
+ grouped_records(association.to_sym, records, polymorphic_parent)
+ .flat_map do |reflection, reflection_records|
+ preloaders_for_reflection reflection, reflection_records, scope
+ end
else
raise ArgumentError, "#{association.inspect} was not recognized for preload"
end
@@ -111,17 +113,15 @@ module ActiveRecord
def preloaders_for_hash(association, records, scope, polymorphic_parent)
association.flat_map { |parent, child|
- loaders = preloaders_for_one parent, records, scope, polymorphic_parent
-
- recs = loaders.flat_map(&:preloaded_records).uniq
-
- reflection = records.first.class._reflect_on_association(parent)
- polymorphic_parent = reflection && reflection.options[:polymorphic]
-
- loaders.concat Array.wrap(child).flat_map { |assoc|
- preloaders_on assoc, recs, scope, polymorphic_parent
- }
- loaders
+ grouped_records(parent, records, polymorphic_parent).flat_map do |reflection, reflection_records|
+ loaders = preloaders_for_reflection(reflection, reflection_records, scope)
+ recs = loaders.flat_map(&:preloaded_records)
+ child_polymorphic_parent = reflection && reflection.options[:polymorphic]
+ loaders.concat Array.wrap(child).flat_map { |assoc|
+ preloaders_on assoc, recs, scope, child_polymorphic_parent
+ }
+ loaders
+ end
}
end
@@ -137,13 +137,11 @@ module ActiveRecord
# Additionally, polymorphic belongs_to associations can have multiple associated
# classes, depending on the polymorphic_type field. So we group by the classes as
# well.
- def preloaders_for_one(association, records, scope, polymorphic_parent)
- grouped_records(association, records, polymorphic_parent).flat_map do |reflection, klasses|
- klasses.map do |rhs_klass, rs|
- loader = preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope)
- loader.run self
- loader
- end
+ def preloaders_for_reflection(reflection, records, scope)
+ records.group_by { |record| record.association(reflection.name).klass }.map do |rhs_klass, rs|
+ loader = preloader_for(reflection, rs).new(rhs_klass, rs, reflection, scope)
+ loader.run self
+ loader
end
end
@@ -151,11 +149,9 @@ module ActiveRecord
h = {}
records.each do |record|
next unless record
- next if polymorphic_parent && !record.class._reflect_on_association(association)
- assoc = record.association(association)
- next unless assoc.klass
- klasses = h[assoc.reflection] ||= {}
- (klasses[assoc.klass] ||= []) << record
+ reflection = record.class._reflect_on_association(association)
+ next if polymorphic_parent && !reflection || !record.association(association).klass
+ (h[reflection] ||= []) << record
end
h
end