Do not do assignment or method calls within cache blocks

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the caching category.

Last Updated: 2021-05-16

Within my product.html.erb view template I had the following cached bit of code that was buggy:

<% cache @product do %>
  <% self.meta_description = @product.meta_description %>
  <h1><%= @product.name %></h1>
  ...
<% end %>

Elsewhere, in the view helper files, this meta_description= setter was defined:

def meta_description=(desc)
  # This effect of this is to generate a lump of content under the `:head` key for
  # insertion into a larger layout (which itself is not cached).
  content_for(:head) do
    %(<meta name="description" content="#{CGI.escapeHTML(desc)}"> ).html_safe
  end
end

The cache in the product.html.erb template did not work as expected: The second time any page was loaded - i.e. when it was loaded from the cache - the page had no "meta description" tag. This was because the :head content key only gets set the first time. All the cache does is remember the final returned HTML - it doesn't call the internal methods again and accumulate their side-effects.

Lesson

Do not "assign" to a variable or generally call any function with a side-effect within a cache block. It will not work.