0.0
No commit activity in last 3 years
No release in over 3 years
Verify cache key dependencies
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

>= 3.2.0
 Project Readme

CacheDebugging Build Status

cache_debugging aims to detangle cache_digests's template dependencies. It currently contains 2 different hooks to check for cache integrity.

StrictDependencies

This module ensures that every render call within a cache block is called on a partial that is in the callers template dependencies.

Why?

We may not have declared all of our explicit template dependencies.

Consider:

cache @workers do
  render @workers
end

Seems reasonable, as it will assume workers/worker is the partial to be depended upon.

We could also declaring the template explicitly:

cache @workers do
  render partial: 'workers/worker', collection: @workers
end

What if, however, @workers is a collection of duck-typed objects that behave like workers? We have to explicitly declare the dependencies:

<%# Template Dependency: plumbers/plumber %>
<%# Template Dependency: gardeners/gardener %>
…
<%# Template Dependency: electricians/electrician %>
cache @workers do
  render @workers
end

How do we ensure that all the possible worker types are declared?

Usage

In application.rb (or environment config):

config.cache_debugging.strict_dependencies = true

We keep track of each cache block with it's dependencies and trigger an ActiveSupport notification (cache_debugging.cache_dependency_missing) if we're rendering a partial not included any parent's template dependencies. You can handle this notification any way you want.

In an initializer:

ActiveSupport::Notifications.subscribe 'cache_debugging.cache_dependency_missing' do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  raise TemplateDependencyException.new(event.payload[:partial], event.payload[:template], event.payload[:dependencies])
end

View Sampling

This module ensures that you have declared all the variable dependencies for your cache block.

Why?

We might be missing a cache variable and not know it.

Consider an view of a bug report ticket that can be assigned:

# tickets/index.html.erb
<% cache @tickets do %>
  <%= render @tickets %>
<% end %>

# tickets/_ticket.html.erb
<% cache ticket do %>
  <tr>
    <td><%= ticket.id %></td>
    <td><%= ticket.title %></td>
    <td><%= ticket.assigned_to.name %></td>
  </tr>
<% end %>

Let's say we decided to replace assigned_to.name with "me" if the ticket is assigned to me. So we update the ticket partial:

# tickets/_ticket.html.erb
<% cache(ticket) do %>
  <tr>
    <td><%= ticket.id %></td>
    <td><%= ticket.title %></td>
    <td><%= ticket.assigned_to == current_user ? "me" : ticket.assigned_to.name %></td>
  </tr>
<% end %>

We've updated the cache block for the singular ticket, but forgotten to update the collection cache block. We won't be notified that we're rendering a different view than we expect.

Usage

In application.rb (or environment config):

config.cache_debugging.view_sampling = 0.1

Every X% of cache hits (10% for the above example), we will re-render the cache block anyways and compare the results. If they don't match, we trigger and ActiveSupport notification (cache_debugging.cache_mismatch). You can handle this notification any way you want.

In an initializer:

ActiveSupport::Notifications.subscribe 'cache_debugging.cache_mismatch' do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  raise CacheMismatchException.new(event.payload[:template], event.payload[:cache_key])
end