Ror Caching
title: Ruby on Rails Caching — Complete Guide to Performance Optimization description: 'Learn Ruby on Rails caching: page caching, fragment caching, Russian doll caching, low-level caching with Redis, HTTP caching, and Turbo Streams caching.' date: 2026-06-28 lastmod: 2026-06-28 weight: 30 tags: [backend, ror]
Rails caching stores fragments of views, whole pages, or query results to reduce database load and dramatically improve response times for repeated requests.
## What You'll Learn
By the end of this tutorial, you'll implement fragment caching, Russian doll caching, low-level Redis caching, HTTP caching with ETags, use Turbo Streams caching, and measure cache effectiveness.
## Real-World Use
A blog site caches post listings (fragment caching), individual posts (Russian doll), and sidebar widgets. First request generates the cache, subsequent requests serve cached content in milliseconds.
## Caching Learning Path
```mermaid
flowchart LR
A[Background Jobs] --> B[Caching]
B --> C[Security]
C --> D[Docker]
D --> E[Deployment]
B --> F{You Are Here}
style F fill:#f90,color:#fff
Fragment Caching
<!-- app/views/posts/index.html.erb -->
<h1>Posts</h1>
<% @posts.each do |post| %>
<% cache post do %>
<article>
<h2><%= link_to post.title, post %></h2>
<p><%= truncate(post.body, length: 200) %></p>
<small><%= time_ago_in_words(post.created_at) %> ago</small>
</article>
<% end %>
<% end %>
<%= cache("posts-count") do %>
<p>Total: <%= Post.published.count %> posts</p>
<% end %>
Russian Doll Caching
<!-- app/views/posts/show.html.erb -->
<% cache @post do %>
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
<div class="comments">
<%= render @post.comments %> <!-- Each comment cached separately -->
</div>
<% end %>
<!-- app/views/comments/_comment.html.erb -->
<% cache comment do %>
<div class="comment">
<p><strong><%= comment.user.name %></strong> said:</p>
<p><%= comment.body %></p>
<small><%= time_ago_in_words(comment.created_at) %> ago</small>
</div>
<% end %>
Low-Level Caching
# app/models/post.rb
class Post < ApplicationRecord
def self.recent_published
Rails.cache.fetch("posts/recent_published", expires_in: 5.minutes) do
published.recent.limit(10).includes(:user).to_a
end
end
def self.category_counts
Rails.cache.fetch("posts/category_counts", expires_in: 1.hour) do
group(:category).count
end
end
end
# In controller
def index
@posts = Rails.cache.fetch("posts/page_#{params[:page]}", expires_in: 1.minute) do
Post.recent_published
end
end
Redis Cache Store
# config/environments/production.rb
config.cache_store = :redis_cache_store, {
url: ENV.fetch("REDIS_URL", "redis://localhost:6379/1"),
expires_in: 1.hour,
namespace: "myapp:cache",
pool_size: 5
}
# Manual cache operations
Rails.cache.write("user_#{user.id}_stats", stats, expires_in: 30.minutes)
stats = Rails.cache.read("user_#{user.id}_stats")
Rails.cache.delete("stale_cache_key")
Rails.cache.clear # Use cautiously in production
Rails.cache.fetch("key", expires_in: 1.hour) { expensive_operation }
HTTP Caching
class PostsController < ApplicationController
# ETag + Last-Modified
def show
@post = Post.find(params[:id])
fresh_when(@post) # Sets ETag and Last-Modified
# Returns 304 Not Modified if client has current version
end
# Conditional GET
def index
@posts = Post.recent
response.headers["Cache-Control"] = "public, max-age=300"
end
end
Common Mistakes
1. Caching Too Broadly
Caching the entire page prevents showing dynamic content (user-specific data). Use fragment caching instead.
2. Not Expiring Caches
Cached data becomes stale. Set expires_in appropriately or use automatic expiry via touch: true.
3. Cache Key Collisions
Without proper cache keys, different content uses the same cache entry. Rails auto-generates keys from model name, id, and updated_at.
4. Not Using Redis in Production
File-based caching (default) is slow and doesn't scale across servers. Use Redis or Memcached.
5. Forgetting to Set Cache Headers
HTTP caching (ETags, Cache-Control) reduces server load from returning clients. Always configure.
Practice Questions
1. What is fragment caching?
Caches parts of a view template. <% cache post do %> caches the rendered HTML for a post record.
2. What is Russian doll caching?
Nested fragment caching. Post fragment contains child comment fragments. Invalidating the parent also invalidates children.
3. How do you manually cache data?
Use Rails.cache.fetch("key", expires_in: 1.hour) { expensive_query } for low-level caching.
4. What are ETags?
HTTP headers that uniquely identify a resource version. Clients send the ETag and get 304 Not Modified if unchanged.
5. Challenge: Implement Russian doll caching for a blog with posts and comments.
<% cache @post do %>
<h1><%= @post.title %></h1>
<%= render @post.comments %> <!-- Each in _comment.html.erb with <% cache comment do %> -->
<% end %>
FAQ
Mini Project: Blog Caching
Implement fragment caching with automatic expiry for a blog.
<% cache @post do %>
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
<p>Updated: <%= @post.updated_at %></p>
<% end %>
What's Next
Ruby on Rails Security Ruby on Rails Docker
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro