aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/test/controller/caching_test.rb12
-rw-r--r--actionview/lib/action_view/helpers/cache_helper.rb15
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb8
3 files changed, 30 insertions, 5 deletions
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 7faf3cd8c6..9c2619dc3d 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -393,9 +393,14 @@ class CollectionCacheController < ActionController::Base
@customers = [Customer.new('david', 1)]
render partial: 'customers/commented_customer', collection: @customers, as: :customer, cached: true
end
+
+ def index_with_callable_cache_key
+ @customers = [Customer.new('david', 1)]
+ render partial: 'customers/customer', collection: @customers, cached: -> customer { 'cached_david' }
+ end
end
-class AutomaticCollectionCacheTest < ActionController::TestCase
+class CollectionCacheTest < ActionController::TestCase
def setup
super
@controller = CollectionCacheController.new
@@ -438,6 +443,11 @@ class AutomaticCollectionCacheTest < ActionController::TestCase
assert_equal 1, @controller.partial_rendered_times
end
+ def test_caching_with_callable_cache_key
+ get :index_with_callable_cache_key
+ assert_customer_cached 'cached_david', 'david, 1'
+ end
+
private
def assert_customer_cached(key, content)
assert_match content,
diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb
index 4eaaa239e2..e28b02f015 100644
--- a/actionview/lib/action_view/helpers/cache_helper.rb
+++ b/actionview/lib/action_view/helpers/cache_helper.rb
@@ -130,9 +130,10 @@ module ActionView
#
# When rendering a collection of objects that each use the same partial, a `cached`
# option can be passed.
+ #
# For collections rendered such:
#
- # <%= render partial: 'notifications/notification', collection: @notifications, cached: true %>
+ # <%= render partial: 'projects/project', collection: @projects, cached: true %>
#
# The `cached: true` will make Action View's rendering read several templates
# from cache at once instead of one call per template.
@@ -142,13 +143,21 @@ module ActionView
# Works great alongside individual template fragment caching.
# For instance if the template the collection renders is cached like:
#
- # # notifications/_notification.html.erb
- # <% cache notification do %>
+ # # projects/_project.html.erb
+ # <% cache project do %>
# <%# ... %>
# <% end %>
#
# Any collection renders will find those cached templates when attempting
# to read multiple templates at once.
+ #
+ # If your collection cache depends on multiple sources (try to avoid this to keep things simple),
+ # you can name all these dependencies as part of a block that returns an array:
+ #
+ # <%= render partial: 'projects/project', collection: @projects, cached: -> project { [ project, current_user ] } %>
+ #
+ # This will include both records as part of the cache key and updating either of them will
+ # expire the cache.
def cache(name = {}, options = {}, &block)
if controller.respond_to?(:perform_caching) && controller.perform_caching
name_options = options.slice(:skip_digest, :virtual_path)
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 f7deba94ce..1fbe209200 100644
--- a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb
@@ -25,9 +25,15 @@ module ActionView
end
end
+ def callable_cache_key?
+ @options[:cached].respond_to?(:call)
+ end
+
def collection_by_cache_keys
+ seed = callable_cache_key? ? @options[:cached] : ->(i) { i }
+
@collection.each_with_object({}) do |item, hash|
- hash[expanded_cache_key(item)] = item
+ hash[expanded_cache_key(seed.call(item))] = item
end
end