未验证 提交 00853808 编写于 作者: K Kasper Timm Hansen 提交者: GitHub

Merge pull request #31250 from lsylvester/only-preload-misses-on-multifetch-cache

Only preload misses on multifetch cache
# 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 @@ class Railtie < Rails::Railtie # :nodoc:
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
......
# 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 @@ class Relation
: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 @@ def alias_tracker(joins = [], aliases = nil) # :nodoc:
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 @@ def exec_queries(&block)
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 @@ def skip_query_cache! # :nodoc:
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 @@ class RelationMutationTest < ActiveRecord::TestCase
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 @@ class RelationMutationTest < ActiveRecord::TestCase
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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册