mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Only preload misses on multifetch cache
This commit is contained in:
parent
a3b7aa66bc
commit
d04a32fe67
6 changed files with 101 additions and 9 deletions
35
actionview/test/activerecord/multifetch_cache_test.rb
Normal file
35
actionview/test/activerecord/multifetch_cache_test.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "active_record_unit"
|
||||
require "active_record/railties/collection_cache_association_loading"
|
||||
|
||||
ActionView::PartialRenderer.prepend(ActiveRecord::Railties::CollectionCacheAssociationLoading)
|
||||
|
||||
class MultifetchCacheTest < ActiveRecordTestCase
|
||||
fixtures :topics, :replies
|
||||
|
||||
def setup
|
||||
view_paths = ActionController::Base.view_paths
|
||||
|
||||
@view = Class.new(ActionView::Base) do
|
||||
def view_cache_dependencies
|
||||
[]
|
||||
end
|
||||
|
||||
def combined_fragment_cache_key(key)
|
||||
[ :views, key ]
|
||||
end
|
||||
end.new(view_paths, {})
|
||||
end
|
||||
|
||||
def test_only_preloading_for_records_that_miss_the_cache
|
||||
@view.render partial: "test/partial", collection: [topics(:rails)], cached: true
|
||||
|
||||
@topics = Topic.preload(:replies)
|
||||
|
||||
@view.render partial: "test/partial", collection: @topics, cached: true
|
||||
|
||||
assert_not @topics.detect { |topic| topic.id == topics(:rails).id }.replies.loaded?
|
||||
assert @topics.detect { |topic| topic.id != topics(:rails).id }.replies.loaded?
|
||||
end
|
||||
end
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue