Ruby on Rails 3 Caching

Cache Configuration

Enable controller caching

Configuration
# True in production (default). False in other environments
config.action_controller.perform_caching = true

ruby on Rails Controller Caching

class AccountsController < ActionController
  # Cache the "index" action
  caches_page :index
  caches_page :show

  def index
     ...
  end

end

When the request is invoked for the first time, Rails generate a file public/action.html. If a web server see the file, it will serve the file directly without the involvement of Rails

To expire the cached page

# Expire the "index" action cache
expire_page :action => :index

caches_page caches HTML page without invoking Rails

caches_action caches pages similar to caches_page but caches_actions will invokes all the Rails filters

caches_action :edit

View Caching

To cache a fragment of a view

View
<% cache do %>
  Content here will be cached
<% end %>

Use action_suffix with different value if more than one caching fragment in a view

<% cache(:action => 'index', :action_suffix => 'frag_content') do %>

To expire fragment

expire_fragment(:controller => 'accounts', :action => 'index',
  :action_suffix => 'frag_content')

Observer to expire cache

class AccountSweeper < ActionController::Caching::Sweeper
  # Listen to events from Account
  observe Account

  # If a account is created
  def after_create(account)
     expire_page :action => :index
  end

  # If an account is updated
  def after_update(product)
     expire_page :action => :index
  end

  # If an account is destroyed
  def after_destroy(account)
     expire_page :action => :index
  end
end

Add the sweeper to a controller

cache_sweeper :account_sweeper, :only => [ :index ]

MemCache

Cached data is stored in separate processes that all servers communicate with

Configuration

config/environments/production.rb
ActionController::Base.cache_store = :mem_cache_store, "localhost"

Http Conditional Get

Use stale? to determine whether we need to render the data or just generate a HTTP NOT MODIFIED

class AccountsController < ApplicationController

  def show
    @account = Account.find(params[:id])

    if stale?(:last_modified => @account.updated_at.utc, :etag => @product)
      respond_to do |format|
         # Server has an updated copy
         # Add code to render view
         format.html
      end
    end

    # If no render has done, the implicit render will check the parameters in the last stale? call
    # If nothing is changed, it just automatically return HTTP code: NOT MODIFIED
end

fresh_when invokes the view only if the content has not changed

class AccountsController < ApplicationController

  def show
    @account = Account.find(params[:id])
    # If not modify, return not modified, else fall back to the default view rendering
    fresh_when :last_modified => @product.published_at.utc, :etag => @account
  end
end