diff options
author | Lachlan Sylvester <lachlan.sylvester@publicisfrontfoot.com.au> | 2017-11-21 15:38:21 +1100 |
---|---|---|
committer | Lachlan Sylvester <lachlan.sylvester@publicisfrontfoot.com.au> | 2018-03-06 14:10:45 +1100 |
commit | d04a32fe67d1d3d5735f9c4f4004c17631e83cc1 (patch) | |
tree | d99a42a32e3b41de6ccacede109f1a2c0bfe55ae /activerecord | |
parent | a3b7aa66bc81da96ea91019540e8874a76216cd8 (diff) | |
download | rails-d04a32fe67d1d3d5735f9c4f4004c17631e83cc1.tar.gz rails-d04a32fe67d1d3d5735f9c4f4004c17631e83cc1.tar.bz2 rails-d04a32fe67d1d3d5735f9c4f4004c17631e83cc1.zip |
Only preload misses on multifetch cache
Diffstat (limited to 'activerecord')
5 files changed, 66 insertions, 9 deletions
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index ade5946dd5..3cef92df5d 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -157,6 +157,14 @@ end_warning end end + initializer "active_record.collection_cache_association_loading" do + require "active_record/railties/collection_cache_association_loading" + ActiveSupport.on_load(:action_view) do + ActionView::PartialRenderer.prepend(ActiveRecord::Railties::CollectionCacheAssociationLoading) + end + end + + initializer "active_record.set_reloader_hooks" do ActiveSupport.on_load(:active_record) do ActiveSupport::Reloader.before_class_unload do diff --git a/activerecord/lib/active_record/railties/collection_cache_association_loading.rb b/activerecord/lib/active_record/railties/collection_cache_association_loading.rb new file mode 100644 index 0000000000..b5129e4239 --- /dev/null +++ b/activerecord/lib/active_record/railties/collection_cache_association_loading.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module ActiveRecord + module Railties # :nodoc: + module CollectionCacheAssociationLoading #:nodoc: + def setup(context, options, block) + @relation = relation_from_options(options) + + super + end + + def relation_from_options(cached: nil, partial: nil, collection: nil, **_) + return unless cached + + relation = partial if partial.is_a?(ActiveRecord::Relation) + relation ||= collection if collection.is_a?(ActiveRecord::Relation) + + if relation && !relation.loaded? + relation.skip_preloading! + end + end + + def collection_without_template + @relation.preload_associations(@collection) if @relation + super + end + + def collection_with_template + @relation.preload_associations(@collection) if @relation + super + end + end + end +end diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 736173ae1b..34e643b2de 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -8,7 +8,8 @@ module ActiveRecord :extending, :unscope] SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, - :reverse_order, :distinct, :create_with, :skip_query_cache] + :reverse_order, :distinct, :create_with, :skip_query_cache, + :skip_preloading] CLAUSE_METHODS = [:where, :having, :from] INVALID_METHODS_FOR_DELETE_ALL = [:distinct, :group, :having] @@ -546,6 +547,16 @@ module ActiveRecord ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins) end + def preload_associations(records) + preload = preload_values + preload += includes_values unless eager_loading? + preloader = nil + preload.each do |associations| + preloader ||= build_preloader + preloader.preload records, associations + end + end + protected def load_records(records) @@ -575,13 +586,7 @@ module ActiveRecord klass.find_by_sql(arel, &block).freeze end - preload = preload_values - preload += includes_values unless eager_loading? - preloader = nil - preload.each do |associations| - preloader ||= build_preloader - preloader.preload @records, associations - end + preload_associations(@records) unless skip_preloading_value @records.each(&:readonly!) if readonly_value diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 3afa368575..4e60863e52 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -899,6 +899,11 @@ module ActiveRecord self end + def skip_preloading! # :nodoc: + self.skip_preloading_value = true + self + end + # Returns the Arel object associated with the relation. def arel(aliases = nil) # :nodoc: @arel ||= build_arel(aliases) diff --git a/activerecord/test/cases/relation/mutation_test.rb b/activerecord/test/cases/relation/mutation_test.rb index 1428b3e132..d6351bfe88 100644 --- a/activerecord/test/cases/relation/mutation_test.rb +++ b/activerecord/test/cases/relation/mutation_test.rb @@ -59,7 +59,7 @@ module ActiveRecord assert_equal [], relation.extending_values end - (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with, :skip_query_cache]).each do |method| + (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with, :skip_query_cache, :skip_preloading]).each do |method| test "##{method}!" do assert relation.public_send("#{method}!", :foo).equal?(relation) assert_equal :foo, relation.public_send("#{method}_value") @@ -137,6 +137,11 @@ module ActiveRecord assert relation.skip_query_cache_value end + test "skip_preloading!" do + relation.skip_preloading! + assert relation.skip_preloading_value + end + private def relation @relation ||= Relation.new(FakeKlass) |