I am a Sr. Software Developer at Oracle Cloud. The opinions expressed here are my own and not necessarily those of my employer.
Rails cache busting
Rails caching is a great tool for scaling websites. We can use different cache stores (Redis and Memcached being common choices).
Using key based cache frees us from writing observers to manually purge the cache. When record is updated it’s cache_key changes, new content is cached and old one is eventually purged using TTL. Here is my previous post about various uses of caching.
To enable it we modify production.rb.
config.cache_store = :readthis_store,
{ expires_in: 1.hour,
namespace: app_cache,
redis: { host: 'host_name', port: 6379, db: 0 },
driver: :hiredis }
Here is a basic CMS with Articles and Comments.
# app/models/article.rb
class Article
field :body
has_many :comments
def comments_count
Rails.cache.fetch([cache_key, __method__]) do
comments.count
end
end
def another_method
Rails.cache.fetch([cache_key, __method__]) do
...
end
end
end
# app/models/comment.rb
class Comment
field :body
belongs_to :article, touch: true
end
We cache comments_count
and use touch: true
to update Article timestamp when new Comment is created/updated/deleted. The problem is it busts cached data for ALL Article methods and view cache as well. We might not want that.
In such cases instead of touch: true
we can implement callbacks on the child record to delete specific cached data for the parent record.
# app/models/comment.rb
class Comment
field :body
belongs_to :article
after_create :article_comments_count
after_destroy :article_comments_count
private
def article_comments_count
cache_key = [article.cache_key, 'comments_count']
Rails.cache.delete(cache_key)
end
end
This will not impact Article timestamp and leave the other cached data in place. We do need to be more careful with this approach as it could lead to situations where only some cached data is deleted but some remains stale until default application TTL removes it. But this can be a useful solution where there is unnecessary cache purging and recreation.