0.0
No commit activity in last 3 years
No release in over 3 years
CachEmAll is a gem which aims to make the use of Rails 4's fragment caching even easier.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

~> 4.0.0
 Project Readme

CachEmAll Build Status Dependency Status Gem Version Code Climate Coverage Status

CachEmAll is a Rails 4️⃣ gem which aims to make the use of Rails 4's fragment caching even easier. Based on the official documentation's tip of counting and getting the last updated record's timestamp, it generates the cache keys for all the the AR records and minifies the cache key generated when you use an AR Relation in the cache helper.

Installation

Add the gem to your gemfile

# Gemfile
gem 'cach_em_all'

Then run bundle install. And you're ready to go.

Usage (why and how)

Let's suppose that your website's footer shows your partners and the acceptable payment types for it's service. Every page loaded demands to load the footer, which will require to load all your payment types and partners. You could use a fragment cache in order to cache your footer, since it will only change when a partner or payment type change. According to caching_with_rails a way to achieve this, without have to worry about fragment expiring, would be to do something like this:

module ApplicationHelper
  def cache_key_for_partners
    count          = Partner.count
    max_updated_at = Partner.maximum(:updated_at).try(:utc).try(:to_s, :number)
    "partners/all-#{count}-#{max_updated_at}"
  end
  def cache_key_for_payment_types
    count          = PaymentType.count
    max_updated_at = PaymentType.maximum(:updated_at).try(:utc).try(:to_s, :number)
    "payment_types/all-#{count}-#{max_updated_at}"
  end
end

Those helpers will generate cache_keys which will persist the same until there is an update in any record, an insertion or a deletion. With those helpers, it's easy to cache the footer (suppose that the footer is a partial called footer):

<% cache [cache_key_for_partners, cache_key_for_payment_types] do %>
  <%= render "footer" %>
<% end %>

Another advantage of this method is the practicity to make Russian Doll Caching:

<% cache(cache_key_for_partners) do %>
  <% Partner.all.each do |partner| %>
    <% cache(partner) do %>
      <%= link_to partner.name, partner_url(partner) %>
    <% end %>
  <% end %>
<% end %>

Using this gem you don't need to write those helpers, all you got to do is pass the name of the ActiveRecord to the cache helper. Our footer example will look like this:

<% cache [Partner, PaymentType] do %>
  <%= render "footer" %>
<% end %>

About using ActiveRecord::Relations, if you pass a Relation to the cache helper, it will convert it to an array, therefore executing the query, and then it will concatenate the individual cache_key of each record, creating something like this to a result with seven elements: products/1-20130717201743/products-2-20130713134532/products-3-20130718211340/products-4-20130719012141/products-5-20130719012201/products-6-20130719012214/products-7-20130719012226 This gem digests the Relation SQL and make ActiveRecord::Relations repond to cache_key with something like this: products/3a0f5b12c290eba6ccc1d30dcaaebf465159d2ae1f76ad01562c245f46204fa0-7-20130719012226

Examples

Russian Doll Caching with an AR called Product:

<% cache(Product) do %>
  <% Product.all.each do |products| %>
    <% cache(product) do %>
      <%= link_to product.name, partner_url(product) %>
    <% end %>
  <% end %>
<% end %>

Caching a footer's partial which only change when there is a change in the records of Partner or PaymentMethod:

<% cache [Partner, PaymentType] do %>
  <%= render "footer" %>
<% end %>

Caching a subset of featured products which are showed by ProductCategory and are changed only with the change in the Product's records. In the following example, the result SQL of the ActiveRecord::Relation is used to generate the cache_key. Note that the relation Product.where(:product_category_id => @product_category.id, :active => true, :featured => true) is passed to the cache helper:

# Product Class
class Product < ActiveRecord::Base
  belongs_to :product_category
  scope :active,    -> { where(active: true) }
  scope :featured,  -> { where(featured: true) }
end

# ProductCategory Class
class ProductCategory < ActiveRecord::Base
  has_many :products, touch: true
end

# View
# http://myawesomeecommerce/product-category/featured
<% cache @product_category.products.active.featured do %>
  # The products
<% end %>

Development

Roadmap

  • AR Calculations results cache
  • Make scaffold generators have an option to generate cached scaffolds
  • Make a config file and it's generator to select what cache features should be included by default and what should be optional

Changes

To see what has changed in recent versions of CacheEmAll, see the CHANGELOG.

Contributing

To see how to contribute to this gem, please read CONTRIBUTING.

Copyright

Copyright © 2013 Oscar Esgalha. See MIT-LICENSE for details.