diff options
author | Kasper Timm Hansen <kaspth@gmail.com> | 2015-06-29 09:41:40 +0200 |
---|---|---|
committer | Kasper Timm Hansen <kaspth@gmail.com> | 2015-06-29 09:41:40 +0200 |
commit | c90c9b2daa133341ad8ceca2d8010ba7d47c4957 (patch) | |
tree | 5de420942c36f327b435761fba41a0f37ac80995 | |
parent | aba43b7da1f45465fc3753225e5c73046342d4ec (diff) | |
parent | da1674576d01f8fe3ad3b448a4c3fa636bcce106 (diff) | |
download | rails-c90c9b2daa133341ad8ceca2d8010ba7d47c4957.tar.gz rails-c90c9b2daa133341ad8ceca2d8010ba7d47c4957.tar.bz2 rails-c90c9b2daa133341ad8ceca2d8010ba7d47c4957.zip |
Merge pull request #20538 from repinel/fix-render-caching-issue
Fix cache issue when different partials use the same collection
-rw-r--r-- | actionview/CHANGELOG.md | 9 | ||||
-rw-r--r-- | actionview/lib/action_view/helpers/cache_helper.rb | 24 | ||||
-rw-r--r-- | actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb | 2 | ||||
-rw-r--r-- | actionview/test/template/render_test.rb | 17 |
4 files changed, 36 insertions, 16 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md index fe47fb47fd..04c0850fba 100644 --- a/actionview/CHANGELOG.md +++ b/actionview/CHANGELOG.md @@ -1,3 +1,12 @@ +* Always attach the template digest to the cache key for collection caching + even when `virtual_path` is not available from the view context. + Which could happen if the rendering was done directly in the controller + and not in a template. + + Fixes #20535 + + *Roque Pinel* + * Improve detection of partial templates eligible for collection caching, now allowing multi-line comments at the beginning of the template file. diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb index 72e2aa1807..8945575860 100644 --- a/actionview/lib/action_view/helpers/cache_helper.rb +++ b/actionview/lib/action_view/helpers/cache_helper.rb @@ -137,7 +137,7 @@ module ActionView # The automatic cache multi read can be turned off like so: # # <%= render @notifications, cache: false %> - def cache(name = {}, options = nil, &block) + def cache(name = {}, options = {}, &block) if controller.respond_to?(:perform_caching) && controller.perform_caching safe_concat(fragment_for(cache_fragment_name(name, options), options, &block)) else @@ -153,7 +153,7 @@ module ActionView # <b>All the topics on this project</b> # <%= render project.topics %> # <% end %> - def cache_if(condition, name = {}, options = nil, &block) + def cache_if(condition, name = {}, options = {}, &block) if condition cache(name, options, &block) else @@ -169,22 +169,23 @@ module ActionView # <b>All the topics on this project</b> # <%= render project.topics %> # <% end %> - def cache_unless(condition, name = {}, options = nil, &block) + def cache_unless(condition, name = {}, options = {}, &block) cache_if !condition, name, options, &block end # This helper returns the name of a cache key for a given fragment cache - # call. By supplying skip_digest: true to cache, the digestion of cache + # call. By supplying +skip_digest:+ true to cache, the digestion of cache # fragments can be manually bypassed. This is useful when cache fragments # cannot be manually expired unless you know the exact key which is the # case when using memcached. - def cache_fragment_name(name = {}, options = nil) - skip_digest = options && options[:skip_digest] - + # + # The digest will be generated using +virtual_path:+ if it is provided. + # + def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil) if skip_digest name else - fragment_name_with_digest(name) + fragment_name_with_digest(name, virtual_path) end end @@ -198,10 +199,11 @@ module ActionView private - def fragment_name_with_digest(name) #:nodoc: - if @virtual_path + def fragment_name_with_digest(name, virtual_path) #:nodoc: + virtual_path ||= @virtual_path + if virtual_path names = Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name) - digest = Digestor.digest name: @virtual_path, finder: lookup_context, dependencies: view_cache_dependencies + digest = Digestor.digest name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies [ *names, digest ] else diff --git a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb index c8268e226e..1147963882 100644 --- a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb +++ b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb @@ -51,7 +51,7 @@ module ActionView end def expanded_cache_key(key) - key = @view.fragment_cache_key(@view.cache_fragment_name(key)) + key = @view.fragment_cache_key(@view.cache_fragment_name(key, virtual_path: @template.virtual_path)) key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0. end diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb index 27bbb9b6c1..9c2c9507b7 100644 --- a/actionview/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -7,7 +7,10 @@ end module RenderTestCases def setup_view(paths) @assigns = { :secret => 'in the sauce' } - @view = ActionView::Base.new(paths, @assigns) + @view = Class.new(ActionView::Base) do + def view_cache_dependencies; end + end.new(paths, @assigns) + @controller_view = TestController.new.view_context # Reload and register danish language for testing @@ -616,7 +619,7 @@ class CachedCollectionViewRenderTest < CachedViewRenderTest test "with custom key" do customer = Customer.new("david") - key = ActionController::Base.new.fragment_cache_key([customer, 'key']) + key = cache_key([customer, 'key'], "test/_customer") ActionView::PartialRenderer.collection_cache.write(key, 'Hello') @@ -626,7 +629,7 @@ class CachedCollectionViewRenderTest < CachedViewRenderTest test "automatic caching with inferred cache name" do customer = CachedCustomer.new("david") - key = ActionController::Base.new.fragment_cache_key(customer) + key = cache_key(customer, "test/_cached_customer") ActionView::PartialRenderer.collection_cache.write(key, 'Cached') @@ -636,11 +639,17 @@ class CachedCollectionViewRenderTest < CachedViewRenderTest test "automatic caching with as name" do customer = CachedCustomer.new("david") - key = ActionController::Base.new.fragment_cache_key(customer) + key = cache_key(customer, "test/_cached_customer_as") ActionView::PartialRenderer.collection_cache.write(key, 'Cached') assert_equal "Cached", @view.render(partial: "test/cached_customer_as", collection: [customer], as: :buyer) end + + private + def cache_key(names, virtual_path) + digest = ActionView::Digestor.digest name: virtual_path, finder: @view.lookup_context, dependencies: [] + @view.fragment_cache_key([ *Array(names), digest ]) + end end |