Our Blog

Ongoing observations by End Point people

A Cache Expiration Strategy in RailsAdmin

By Steph Skardal
March 16, 2012

I’ve been blogging about RailsAdmin a lot lately. You might think that I think it’s the best thing since sliced bread. It’s a great configurable administrative interface compatible with Ruby on Rails 3. It provides a configurable architecture for CRUD (create, update, delete, view) management of resources with many additional user-friendly features like search, pagination, and a flexible navigation. It integrates nicely with CanCan, an authorization library. RailsAdmin also allows you to introduce custom actions such as import, and approving items.

Whenever you are working with a gem that introduces admin functionality (RailsAdmin, ActiveAdmin, etc.), the controllers that provide resource management do not live in your code base. In Rails, typically you will see cache expirations in the controller that provides the CRUD functionality. For example, in the code below, a PagesController will specify caching and sweeping of the page which expires when a page is updated or destroyed:

class PagesController < AdminController
  caches_action :index, :show
  cache_sweeper :page_sweeper, :only => [ :update, :destroy ]


While working with RailsAdmin, I’ve come up with a different solution for expiring caches without extending the RailsAdmin functionality. Here are a couple of examples:

Page Caching

On the front-end, I have standard full page caching on static pages. In this case, the config/routes.rb maps wildcard paths to the pages controller and show action.

match '*path' => 'pages#show'

The controller calls the standard caches_page method:

class PagesController < ApplicationController
  caches_page :show

  def show
    @page = Page.find_by_slug(params[:path])

A simple ActiveRecord callback is added to clear the page cache:

class Page < ActiveRecord::Base

  after_update :clear_cache

  def clear_cache

Fragment Caching

When a page can’t be fully cached, I might cache a view shared across the application. In the example below, the shared view is included in the layout—​it’s generated dynamically but the data does not change often, which makes it suitable for fragment caching.

<% cache  "navigation" do -%>
  <% Category.each do |category| -%>
    <%= link_to category.name, category_url(category) %>
  <% end -%>
<% end  -%>

Inside the model, I add the following to clear the fragment cache when a category is created, updated, or destroyed:

class Category < ActiveRecord::Base
  after_create :clear_cache
  after_update :clear_cache
  before_destroy :clear_cache

  def clear_cache


One thing that’s noteworthy is that expire_page requires a class method on ActionController::Base while expire_fragment requires an instance method (see here versus here). Action cache expiration with ActiveRecord callbacks should work similarly with action caching, as a class method (reference).

An alternative approach here would be to extend the generic RailsAdmin admin controller to introduce a generic sweeper. However, the sweeper would have to determine what model was modified and what to expire it. This can be implemented and abstracted elegantly, but in my application I preferred to use simple ActiveRecord callbacks because the caching was limited to a small number of models.



Popular Tags


Search our blog