How to setup and use Rack::Cache with Rails

Add Rack::Cache to your Gemfile: ```ruby gem 'rack-cache', :require => 'rack/cache' ``` Configure Rails to use Rack::Cache by adding this to config/environment.rb: ```ruby config.middleware.use Rack::Cache, :verbose => true, :metastore => 'file:/var/cache/rack/meta', :entitystore => 'file:/var/cache/rack/body' ``` This will cache content in /var/cache/rack/meta. Check the documentation for [instructions on how to use memcached](https://github.com/rtomayko/rack-cache#readme). ### Verify configuration Verify the configuration: ```ruby rake middleware ``` You should see something like this: ```ruby … use Rack::Cache, {:metastore=>"file:/var/cache/rack/meta", :entitystore=>"file:/var/cache/rack/body", :verbose=>true} … ``` ### Tell Rack::Cache to cache your content Tell Rack to cache data by calling expires\_in from your controller's action or from a Rails filter: ```ruby expires_in 5.minutes, :public => true ``` Rails sets cache-control to private by default, Rack::Cache needs public content. ### Don't cache private data Note that you must be careful not to cache private data when a user is signed in. In this case you should set the Cache-Control header to private or completely avoid using expires\_in: ```ruby fail "Don't cache private data" if signed_in? expires_in 5.minutes, :public => true ``` ### Verify caching With verbose set to true, you'll see this in the logs: ```ruby [cache] trace: cache miss [cache] trace: fetching response from backend [cache] trace: store backend response in cache (ttl: 300s) [cache] trace: storing response in cache [cache] trace: delivering response ... [cache] trace: cache hit (ttl: 276s) [cache] trace: delivering response ... ``` ### Caching more than one type of content Make sure you cache e.g. HTML and JSON separately. You could use the Vary HTTP header to achieve this: ```ruby response.headers['Vary'] = 'Accept' ``` The problem is that almost every browser version has a unique Accept header. Instead you could try using the cache\_key configuration option to generate a cache key per content type: ```ruby :cache_key => lambda { |request| Rack::Cache::Key.new(request).generate + ":jebus" } ``` You could also add the format request parameter to the URL, e.g. /json-and-html?format=html ### Advanced configuration In production you probably want to disallow reloading of content. This can be done with the following configuration options: ```ruby config.middleware.use Rack::Cache, :metastore => 'file:/var/cache/rack/meta', :entitystore => 'file:/var/cache/rack/body', :allow_reload => false, :allow_revalidate => false, ``` Read the source ([options.rb](https://github.com/rtomayko/rack-cache/blob/master/lib/rack/cache/options.rb)) for more advanced configuration options (ignore\_headers, private\_headers, etc). ### References [HTTP RFC - Cache-Control](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1) [Rack::Cache options documentation](http://tomayko.com/src/rack-cache/api/classes/Rack/Cache/Options.html) [Rails expires\_in documentation](http://api.rubyonrails.org/classes/ActionController/Base.html#M000666) [HTTP Vary Header](http://www.subbu.org/blog/2007/12/vary-header-for-restful-applications)