Christian Fazzini
Christian Fazzini

Reputation: 19723

How would you expire fragment caches in the model or in a Resque worker?

I've taken the quote below, which I can see some sense in:

"Cached pages and fragments usually depend on model states. The cache doesn't care about which actions create, change or destroy the relevant model(s). So using a normal observer seems to be the best choice to me for expiring caches."

For example. I've got a resque worker that updates a model. I need a fragment cache to expire when a model is updated / created. This can't be done with a sweeper.

However, using an observer will mean I would need something like, either in the model or in the Resque job:

ActionController::Base.new.expire_fragment('foobar')

The model itself should not know about caching. Which will also break MVC principles that will lead to ugly ugly results down the road.

Upvotes: 2

Views: 2321

Answers (4)

austen
austen

Reputation: 3314

You can auto-expire the cache by passing the model as an argument in your view template:

<% cache @model do %>
  # your code here
<% end %>

What's happening behind the scenes is a cache named [model]/[id]-[updated_at] is created. Models have a method cache_key, which returns a string containing the model id and updated_at timestamp. When a model changes, the fragment's updated_at timestamp won't match and the cache will re-generate.

This is a much nicer approach and you don't have to worry about background workers or expiring the cache in your controllers/observers.

Ryan Bates also has a paid Railscast on the topic: Fragment Caching

Upvotes: 3

Ismael
Ismael

Reputation: 16730

A good and simple solution would be not to expire but to cache it with a key that will be different if the content is different. Here is an example

<% cache "post-#{@post.id}", @post.updated_at.to_i do %>

When that post gets updated or deleted and you fetch it again, it will miss the cache since the hash is different, so it will kind of expire and cache the new value. I think you can have some problems by doing this, for example if you are using the Rails default cache wich creates html files as cache, so you would end up with a lot of files in your public dir after some time, so you better set your application to use something like memcached, wich manages memory deleting old cached records/pages/parcials if needed to cache others or something like that.

Upvotes: 2

Kevin Bedell
Kevin Bedell

Reputation: 13424

I'd recommend reviewing this section on sweepers in the Rails Guide - Caching with Rails: An overview

http://guides.rubyonrails.org/caching_with_rails.html#sweepers

It looks like this can be done without specifically creating lots of cache expiration observers.

Upvotes: 0

Larry K
Larry K

Reputation: 49114

Use an ActiveRecord::Observer to watch for model changes. It can expire the cache.

Upvotes: 3

Related Questions