Page Caching with Rails and Passenger

This page documents my favorite way of handling page caching with Rails and Passenger. It’s a simple and elegant technique if cache invalidation is infrequent and you can afford to sweep the entire cache once it happens. I’d appreciate any feedback on this article – just contact me.

Step 0: Start page caching

Use cache_page or caches_page in your controllers.

Step 1: Write cached files into public/cache

I don’t like polluting the public directory of my Rails applications with cache files so I dedicate a public/cache directory for them. Add this to your application configuration:

config.action_controller.page_cache_directory = "#{Rails.root}/public/cache"

Note: Replace Rails.root with RAILS_ROOT if you’re running an old version of Rails.

Step 2: Sweep your cache

class CacheSweeper < ActiveRecord::Observer
  observe YourModel, YourSuperModel

  def self.sweep_cache!
    pattern = "#{ActionController::Base.page_cache_directory}/**/*.html" 

    Dir.glob(pattern) do |filename|
      File.delete(filename)
    end
  end

  def after_save(*_)
    self.class.sweep_cache!
  end 

  def after_destroy(*_)
    self.class.sweep_cache!
  end 
end

Activate this observer with config.active_record.observers or invoke CacheSweeper.sweep_cache! yourself. Please note that it sweeps the entire cache.

Step 3: Configure Apache and Passenger

RailsAllowModRewrite On  
RewriteEngine On

RewriteCond %{THE_REQUEST} ^(GET|HEAD)
RewriteCond %{REQUEST_URI} ^/([^.]+)$
RewriteCond %{DOCUMENT_ROOT}/cache/%1.html -f
RewriteRule ^/[^.]+$ /cache/%1.html [QSA,L]

RewriteCond %{THE_REQUEST} ^(GET|HEAD)
RewriteCond %{DOCUMENT_ROOT}/cache/index.html -f
RewriteRule ^/$ /cache/index.html [QSA,L]

Use RewriteLogLevel and RewriteLog if you need to troubleshoot mod_rewrite.

Page History