From 99d260298c3b70d70042c872841b5e81c938fd5b Mon Sep 17 00:00:00 2001
From: schneems <richard.schneeman+foo@gmail.com>
Date: Fri, 7 Sep 2018 14:03:41 -0500
Subject: Move digest path calculation out of loop
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

On every iteration of generating a cache for a collection a “digest path” is calculated even though it’s exactly the same for every element.

This PR exposes a method `digest_path_from_virtual` that returns back a “digest_path”. This can in turn be passed back into `cache_fragment_name`. This not only does less work, but it also (you guessed it) uses  less memory.

before: Total allocated: 762539 bytes (7035 objects)
after: Total allocated: 743590 bytes (6621 objects)


(762539 - 743590)/ 762539.0 # => 2.4% faster ⚡️⚡️
---
 actionview/lib/action_view/helpers/cache_helper.rb | 26 ++++++++++++++--------
 .../partial_renderer/collection_caching.rb         |  6 ++++-
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb
index 15d187a9ec..b1a14250c3 100644
--- a/actionview/lib/action_view/helpers/cache_helper.rb
+++ b/actionview/lib/action_view/helpers/cache_helper.rb
@@ -208,27 +208,35 @@ module ActionView
       #
       # The digest will be generated using +virtual_path:+ if it is provided.
       #
-      def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil)
+      def cache_fragment_name(name = {}, skip_digest: nil, virtual_path: nil, digest_path: nil)
         if skip_digest
           name
         else
-          fragment_name_with_digest(name, virtual_path)
+          fragment_name_with_digest(name, virtual_path, digest_path)
+        end
+      end
+
+      def digest_path_from_virtual(virtual_path) # :nodoc:
+        digest = Digestor.digest(name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies)
+
+        if digest.present?
+          "#{virtual_path}:#{digest}"
+        else
+          virtual_path
         end
       end
 
     private
 
-      def fragment_name_with_digest(name, virtual_path)
+      def fragment_name_with_digest(name, virtual_path, digest_path)
         virtual_path ||= @virtual_path
 
-        if virtual_path
+        if virtual_path || digest_path
           name = controller.url_for(name).split("://").last if name.is_a?(Hash)
 
-          if digest = Digestor.digest(name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies).presence
-            [ "#{virtual_path}:#{digest}", name ]
-          else
-            [ virtual_path, name ]
-          end
+          digest_path ||= digest_path_from_virtual(virtual_path)
+
+          [ digest_path, name ]
         else
           name
         end
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 db52919e91..3c10e0452f 100644
--- a/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer/collection_caching.rb
@@ -40,10 +40,14 @@ module ActionView
       end
 
       def expanded_cache_key(key)
-        key = @view.combined_fragment_cache_key(@view.cache_fragment_name(key, virtual_path: @template.virtual_path))
+        key = @view.combined_fragment_cache_key(@view.cache_fragment_name(key, virtual_path: @template.virtual_path, digest_path: digest_path))
         key.frozen? ? key.dup : key # #read_multi & #write may require mutability, Dalli 2.6.0.
       end
 
+      def digest_path
+        @digest_path ||= @view.digest_path_from_virtual(@template.virtual_path)
+      end
+
       def fetch_or_cache_partial(cached_partials, order_by:)
         order_by.map do |cache_key|
           cached_partials.fetch(cache_key) do
-- 
cgit v1.2.3