The Cedar stack gives us more flexibility but does not use Varnish or Nginx to help with caching and speed. To improve your application's response time and decrease load, you can use Rack::Cache. This is especially important if you're serving static assets through your application, such as images, stylsheets, and javascript through the Rails asset pipeline.
Rails 3+ and other Ruby web frameworks, such as Sinatra, are built on top of Rack. At a high level, Rack works by taking a request and passing it through a series of steps, called middleware. Each Rack middleware performs some action then passes the request to the next level in the rack. Eventually the request is properly formatted and it will reach your Rails application, where your application can handle the request. Rack is written to be lightweight and flexible. If a Rack middleware can respond to a request directly from a Rack middleware, then it doesn't have to hit your Rails application. This means that the request is retuned faster, and the overall load on the Rails application is decreased. Rack::Cache is middleware that enables HTTP caching on your application and can allow us to serve assets from a storage backend without requiring work from your main Rails application.
Rack::Cache can be used with different storage backends. By default Rack::Cache will try to use the file system, which is read only on most of the Heroku platform, and on Cedar is ephemeral. Using memcache as a backend will allow you to persist your cache between deploys, across dynos, and will prevent a slow down on initial requests while warming the cache. Therefore Heroku recommends using Memcache with the Dalli gem as your Rack::Cache backend. Once you have configured your application to use memcached, you can configure Rack::Cache for use in your application.
For Rails 3.1+ you will need to modify your config/production.rb to tell rack_cache to use Memcache. By default Dalli will look for the proper environment variables when deployed to Heroku, and otherwise will default to localhost and the default port. If you want, rather than specifying an object, you can pass the connection string needed to talk to an external memcache server.
:::term
# This will tell `Rack::Cache` to use the default settings of Dalli, Heroku's prefered Memcache Gem
config.action_dispatch.rack_cache = {
:metastore => Dalli::Client.new,
:entitystore => Dalli::Client.new,
:allow_reload => false }
Then you need to set config.servestatic_assets to true.
:::term
# This will allow Action::Dispatch to serve files from /public when set to true
config.serve_static_assets = true
Finally you need to tell the cache how long an item should stay in cache by setting the Cache-Control headers. Without a Cache-Control header, static files will not be stored by Rack::Cache
:::term
# This will set Cache-Control headers used by browsers
config.static_cache_control = "public, max-age=2592000"
Since these settings will tell Rack::Cache to store static elements for a very long time, it is important that you let your cache store know when you change a file. Typically cache invalidation can be very tricky, so to avoid that problem you can ensure that Rails generates a new file name every time you modify a file. This is done by using a hash digest such as MD5 on your files, tell Rails to do this automatically by setting config.assets.digest.
:::term
# Generate digests for assets URLs
config.assets.digest = true
You also want to ensure that caching is turned on.
# Enables caching including Rack::Cache
config.action_controller.perform_caching = true
Once all of this is set up correctly, you should see lines like this in your log.
:::term
# The item was not found in cache (miss) but has been saved for next request (store)
cache: [GET /assets/application-95bd4fe1de99c1cd91ec8e6f348a44bd.css] miss, store
cache: [GET /assets/application-95fca227f3857c8ac9e7ba4ffed80386.js] miss, store
cache: [GET /assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png] miss, store
:::term
# The item was found in cache (fresh) and will be served from cache
cache: [GET /assets/application-95bd4fe1de99c1cd91ec8e6f348a44bd.css] fresh
cache: [GET /assets/application-95fca227f3857c8ac9e7ba4ffed80386.js] fresh
cache: [GET /assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png] fresh
If a setting is not configured properly, you might see miss in your logs instead of store or fresh like this. Make sure that you're using a hard refresh to clear your browser cache while you're investigating the problem.
:::term
cache: [GET /assets/application-95bd4fe1de99c1cd91ec8e6f348a44bd.css] miss
cache: [GET /assets/application-95fca227f3857c8ac9e7ba4ffed80386.js] miss
cache: [GET /assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png] miss
When this happens, ensure that the Cache-Control header exists, copy one of your asset urls and curl it in the terminal using -I which will return the headers. If you can run your app in production mode locally it would look like this:
:::term
$ curl 'http://localhost:3000/assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png' -I
The result should look something like this, where Cache-Control returns public, max-age=2592000
:::term
$ curl 'http://localhost:3000/assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png' -I
HTTP/1.1 200 OK
Last-Modified: Sun, 18 Mar 2012 00:19:19 GMT
Content-Type: image/png
Cache-Control: public, max-age=2592000
Content-Length: 6646
Date: Sun, 18 Mar 2012 21:27:07 GMT
X-Content-Digest: 501d6b0108b930264e19f37cb8ee6c8222d4f30d
Age: 689
X-Rack-Cache: fresh
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Connection: Keep-Alive
You can also ensure that you are seeing and X-Rack-Cache header indicating the status of your asset (fresh/store/miss).
If you modify a file and your server continues to serve the old file, check that you committed the file to your Git repository before deploying, and you can check to see if it exists in your compiled code by using heroku run bash
:::term
$ heroku run bash
Running bash attached to terminal... up, run.1
~ $ ls public/assets
application-95bd4fe1de99c1cd91ec8e6f348a44bd.css application.css manifest.yml
application-95bd4fe1de99c1cd91ec8e6f348a44bd.css.gz application.css.gz rails-782b548cc1ba7f898cdad2d9eb8420d2.png
application-95fca227f3857c8ac9e7ba4ffed80386.js application.js rails.png
application-95fca227f3857c8ac9e7ba4ffed80386.js.gz application.js.gz
Don't forget to check if the file exists in your manifest.yml
:::term
~ $ cat public/assets/manifest.yml
rails.png: rails-782b548cc1ba7f898cdad2d9eb8420d2.png
application.js: application-95fca227f3857c8ac9e7ba4ffed80386.js
application.css: application-95bd4fe1de99c1cd91ec8e6f348a44bd.css
If the file you're looking for does not show up try running rake assets:precompile locally and ensure that it is in your own public/assets directory.

Great stuff. Few comments:
heroku addons:add memcachepart of the process inline here instead of linking out to http://devcenter.heroku.com/articles/memcache#using_memcache_from_ruby. The pattern here is to include the link for more background on Memcached in a callout: http://devcenter.heroku.com/articles/writing#calloutsMEMCACHE_SERVERSin a.envetc...). Minus installing memcached locally, I think we should cover it. Many of our tutorials have the pattern of describing code, running locally and deploying - we should try and mimic.MEMCACHE_SERVERSenv var? If not - how can you just sayDalli::Client.newin the rack-cache config?