aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations/preloader.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/associations/preloader.rb')
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb40
1 files changed, 30 insertions, 10 deletions
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index c7ab926f56..03c66cab4f 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -105,22 +105,36 @@ module ActiveRecord
def preload(association, records)
case association
when Hash
- preload_hash(association, records)
+ preload_hash(association, records).each(&:run)
when Symbol
- preload_one(association, records)
+ preloaders_for_one(association, records).each(&:run)
when String
- preload_one(association.to_sym, records)
+ preloaders_for_one(association.to_sym, records).each(&:run)
else
raise ArgumentError, "#{association.inspect} was not recognised for preload"
end
end
- def preload_hash(association, records)
+ def preloaders_for_hash(association, records)
parent, child = association.to_a.first # hash should only be of length 1
- preload_one parent, records
- run_preload Array.wrap(child),
- records.map { |record| record.send(parent) }.flatten.compact.uniq
+ loaders = preloaders_for_one parent, records
+
+ recs = loaders.flat_map(&:target_records).uniq
+ lls = Array.wrap(child).flat_map { |assoc|
+ case assoc
+ when Hash then preloaders_for_hash(assoc, recs)
+ when Symbol then preloaders_for_one(assoc, recs)
+ when String then preloaders_for_one(assoc.to_sym, recs)
+ else
+ raise
+ end
+ }
+ loaders + lls
+ end
+
+ def preload_hash(association, records)
+ preloaders_for_hash(association, records).each(&:run)
end
# Not all records have the same class, so group then preload group on the reflection
@@ -131,9 +145,15 @@ module ActiveRecord
# classes, depending on the polymorphic_type field. So we group by the classes as
# well.
def preload_one(association, records)
- grouped_records(association, records).each do |reflection, klasses|
- klasses.each do |klass, rs|
- preloader_for(reflection).new(klass, rs, reflection, preload_scope).run
+ preloaders_for_one(association, records).each { |loader|
+ loader.run
+ }
+ end
+
+ def preloaders_for_one(association, records)
+ grouped_records(association, records).flat_map do |reflection, klasses|
+ klasses.map do |rhs_klass, rs|
+ preloader_for(reflection).new(rhs_klass, rs, reflection, preload_scope)
end
end
end