Caching Fragments

Posted by Flatiron School  /  January 15, 2013

The following is a guest post by Li Ouyang and originally appeared on her blog. Li is currently a student a The Flatiron School. You can learn more about her here, or follow her on twitter here.

In order to speed up performance, sometimes you’ll want to cache a page. Once the data changes, the cached page should expire, in order to show the new information. Rails has some features built in to help us with this. One of which are Sweepers. The Rails API claims this:

Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change. They do this by being half-observers, half-filters and implementing callbacks for both roles.

However, much to my dismay, if an object was edited or created outside of the controller, the sweeper doesn’t seem to pick it up, despite the Rails documentation. This means cron jobs or objects created/edited in console doesn’t trigger the sweeper, and you’re left with stale cached pages. After digging through many stackoverflow threads, like this one, it seems like I wasn’t the only one to struggle with this.

However, I did find a workaround: fragment caching! Thanks to Ryan Bates for another great railscast.

Modify the configuration file and set perform_caching = true.

Blog post image: tumblr_inline_mgofkqyjIM1rtan47.png

To cache a fragment of any view, simply wrap the code with <% cache 'something' do %> <% end %>. The fragment will be cached with whatever you want to call it. Let’s say you want automatic expiration. You can do this by replacing 'something' with something like this.

Blog post image: tumblr_inline_mgofl3kppC1rtan47.png

Automatic expiration works here because of key-based expiration. Check it out by going to console and typing in song.cache_key.

Blog post image: tumblr_inline_mgofl9PdHm1rtan47.png

The cache_key is updated through the updated_at timestamp. So the line <% cache song do %> checks to see if there is a fragment that is the same as song.cache_key. If not, it generates a new one, and expires the old one. More information about cache keys from DHH himself here.

One thing to be careful of is the naming of fragments. If you’re caching on multiple templates, chances are you might accidently create a fragment with the same name. To get around that, prepend a string by using an array.

Blog post image: tumblr_inline_mgoflfjUhE1rtan47.png

In our case, song belongs to a mixtape. So in the song.rb file I’ve added a touch: true to the association, to ensure the associated model, mixtape, gets updated everytime the song gets updated.

Blog post image: tumblr_inline_mgoflwdvB51rtan47.png

While you’re testing caching, you may notice your changes not going through. Be sure to Rails.cache.clear everytime you change the code regarding caching. Interesting? Read more about advanced caching here