Caching is the most reliable way to make a Rails app fast: a request that runs less Ruby finishes sooner. It is also an easy way to serve stale or wrong pages. These are the practices worth keeping.
This page is our summary of Nate Berkopec's The Complete Guide to Rails Caching at Speedshop. Read the original for the benchmarks and the full reasoning; the wording here is ours.
Start with a number. Pick a target for average response time, then find which pages miss it. The Rails log
splits each request into view and database time; rack-mini-profiler (with flamegraphs) shows exactly
where the time goes. Profile in production mode with realistic data, since development mode and a nearly empty
database both lie about speed. Cache only what the measurements point at.
Caching speeds up pages people view. It does nothing for a slow form submission or API write. When a write does heavy work, move that work into a background job instead.
Wrap the expensive parts of a view in cache blocks. Page and action caching were taken out of
Rails core in Rails 4 because they fit so few real pages; fragments cover nearly everything they did.
<% cache product do %>
<%= render product %>
<% end %>
Don't delete cache entries by hand. Build the key from everything the content depends on, so a change produces
a new key and the old entry is simply never read again. Rails does this for records by default: the key includes
the model, its id, its last update and a digest of the template, so editing the view busts the cache too. Pass an
array when a fragment depends on more than one thing, such as [product, current_user].
"Russian doll" caching nests fragments inside fragments. When one item in a list changes, only its fragment and
the list around it rebuild; every other item comes straight from the cache. For that to work, a change to a child
record has to update its parent, which is what touch: true does:
class Comment < ApplicationRecord
belongs_to :post, touch: true
end
Forgetting a touch is the classic way to end up with a page that never updates.
Where the cache lives matters as much as what goes in it.
Memory store: the fastest, but each process has its own copy and it uses app memory. Fine for small caches on one or two servers.
File store: shared between processes on one machine and cheap, but slow, and it doesn't evict the least-used entries, which key-based expiration relies on. Avoid it on hosts with throwaway disks.
Memcached or Redis: shared by every server, at the cost of a network hop on each read. Memcached caps values at 1 MB; Redis offers more eviction policies and can persist to disk.
Since the guide was written, Rails has gained a built-in Redis store (5.2) and Solid Cache, a database-backed store that is the default in new Rails 8 apps.
A remote cache read is not free. Under load it can cost more than just rendering a small partial. If a fragment is quick to build, leave it uncached; measure the read cost of your store before wrapping everything.
Cache bugs live where pieces meet: a missing dependency in a key, a parent that never gets touched. Those are the spots unit tests skip, so check them with tests that change a record and confirm the page changes too.
This site is a static Rack app, so it uses HTTP caching instead: every file gets an ETag and
Cache-Control: no-cache, so browsers keep a copy but ask each time whether it changed, and get an
empty 304 Not Modified when it hasn't.
Provided as is, for information only, with no warranty and no liability. Not legal or professional advice. Security and radio material is for authorized, lawful use only. Full disclaimer.
Visits are logged on our own server: IP address, browser and device details, and pages viewed. We use them to understand traffic and spot attacks, and never share or sell them.