Key-based cache expiration in
Rails 4...or Rails 3 with a dependency
Wednesday, July 31, 13
Building Blocks (ActiveRecord::Base)
@product.cache_key
=> “products/1281-20130717091609”
“#{name}/#{id}-#{timestamp}”
Wednesday, July 31, 13
Building Blocks (ActionView::Helpers::CacheHelper)
- cache @product do %h1= @product.name = image_tag @product.image.url
Wednesday, July 31, 13
Write fragment views/products/1-20130728191246157664000
(“views/#{cache_key}”)
- cache @product do %h1= @product.name = image_tag @product.image.url
Wednesday, July 31, 13
You can compose fragment keys, too...
- cache [@product, “reviews”] do %h1= @product.name = image_tag @product.image.url
Write fragment views/products/1-20130728191246157664000/reviews
“views/#{cache_key}/#{extra_args.join(‘/’)}”
Wednesday, July 31, 13
“But what if I change a template?”
Wednesday, July 31, 13
Rails.cache.clear
Wednesday, July 31, 13
“But what if I deploy 5 times a day”
Wednesday, July 31, 13
sucks
Wednesday, July 31, 13
Just kidding!™
Wednesday, July 31, 13
# Gemfile
gem ‘pg’
gem ‘cache_digests’
gem ‘haml-rails’
gem ‘cancan’
# ...
(Rails 3 only – built into actionpack 4)
Wednesday, July 31, 13
Write fragment views/products/1-20130728191246157664000/3b2b93d56d331aa7a1bf9267a656d3c9
(“views/#{cache_key}/#{template_digest}”)
- cache @product do %h1= @product.name = image_tag @product.image.url
With cache_digests...
note: template_digest is a digest of the current template and all of it’s dependencies (more on that later)Wednesday, July 31, 13
Cache digest for products/_product.html: 42eb891316f21e68798de5d5aa8021d5
Read fragment views/products/1-20130728191246157664000/42eb891316f21e68798de5d5aa8021d5
Write fragment views/products/1-20130728191246157664000/42eb891316f21e68798de5d5aa8021d5
- cache @product do %h1= @product.name - # image_tag @product.image.url
...change the template
Wednesday, July 31, 13
template change-> new digest
-> new fragment key-> busted cache!
Wednesday, July 31, 13
And we didn’t have to do anything!
Wednesday, July 31, 13
“Russian doll” caching strategythe notorious
Wednesday, July 31, 13
class Product < ActiveRecord::Base has_many :reviewsend
class Review < ActiveRecord::Base belongs_to :product, touch: trueend
Product’s cache key now dependent on its reviews
Wednesday, July 31, 13
@review.update!(rating: 3)
@review.product’s key gets bumped as well
Wednesday, July 31, 13
the “russian doll”...
# products/index.haml
- cache [@products.order(“updated_at ASC”).last, “index”] do%ul.products
- @products.each do |product| = render product
# products/_product.haml
- cache product do %li.product %h1= product.name %h2 Reviews! %ul.reviews - product.reviews.each do |review| = render review
# reviews/_review.haml
- cache review do %li.review %h4= “#{review.rating} stars!” %p.content= review.content
Wednesday, July 31, 13
the “russian doll”...index
product
reviews list
review
review
review
Wednesday, July 31, 13
@product.reviews.last.update!(rating: 5)
Last review will get re-rendered (and cached) and container (review list) will get busted -
but when list re-renders all but this last review can be fetched from cache.
Wednesday, July 31, 13
View the template dependency tree...
$ rake cache_digests:nested_dependencies TEMPLATE=your/template/name
ex:
and rake task for Rails 4: https://gist.github.com/nzaillian/6127613
Wednesday, July 31, 13
Explicit dependencyIf Rails just can’t seem to figure out your dependency you can declare an explicit dependency in a template by including a comment with a special form:
- # Template Dependency: reviews/summary
(...but you shouldn’t ever have to do this)
Wednesday, July 31, 13
Other Resourceshttps://github.com/rails/cache_digests
http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works
http://www.youtube.com/watch?v=yhseQP52yIY&t=0:39:39
must watch! (DHH’s Railsconf 2013 outline of key-based caching)
http://api.rubyonrails.org/classes/ActionView/Helpers/CacheHelper.html
Wednesday, July 31, 13
Top Related