11 April 2013

rails caching

by mo


Options

  • HTTP Caching: Uses HTTP headers to instruct browsers on server side caching.
  • Page Caching: Cache the entire page to disk and serve directly from the web server like Nginx.
  • Action Caching: Runs through the rails pipeline and runs before_filters but returns cached results from disk like page caching.
  • Fragment Caching: Store parts of views in the cache.
  • Rails.cache: In memory server side cache.

Page Caching

class ProductsController < ActionController
  caches_page :index

  def index
    @products = Products.all
  end 
end
  • /products will generate a file called products.html.gz. NGINX will efficiently serve this static file
  • by default pages are cached in /public

To expire a page you call expire_page in the action that would invalidate the cache.

class ProductsController < ActionController
  caches_page :index

  def index
    @products = Products.all
  end 

  def create
    expire_page :action => :index
  end
end

Nginx can serve compressed content directly from disk by enabled gzip_static

  location / {
    gzip_static on;
  }

Page caching ignores parameters like /products?page=1. If someone requests /products?page=2 they will get the cached first page. A workaround is to use a route like /products/page/1

Action Caching

This is good for pages that restrict access in some way. Incoming request does go from webserver to rails stack. Before filters are run to allow for things like authentication. Instead of expire_page you use expire_action.

class ProductsController < ActionController
  before_filter :authenticate
  caches_action :index

  def index
    @products = Product.all
  end

  def create
    expire_action :action => :index
  end
end

Fragment Caching

Add cache “key” to your view to cache a fragment. You can use the updated_at timestamp to signal when to invalidate the cache.

<%= cache "post-#{@post.id}", @post.updated_at.to_i do %>
  <h1><%= @post.title %></h1>
  <p><%= @post.content %></p>
<% end %>

If you touch a post it will update the timestamp.

  Post.find(2).touch

  class Comment < ActiveRecord::Base
    belongs_to :post, :touch => true
  end

Rails Cache

  Rails.cache.write('foo', 'bar')
  Rails.cache.read('foo')
  Rails.cache.clear
💎