skip down to the 1 comment

expires_in Rails FileStore fragment caching in about 6 lines

I have been building a Rails app that creates RSS feeds based on a lot of screen scraping behind the scenes. I really needed a way to cache the data object that feeds those specific pages. In rails you can do page, action and fragment caching, using many different methods, and storing that cache data in many different locations.

After deciding I needed Fragment caching, it turns out that if you need your cache data to magically expire over time, you need to be using memcached (I couldn’t), other wise you have to roll you own solution, based on cache sweeping, or in-code testing of whether your content has expired.

I’m using FileStore for caching (cached files live on the file system) and I have no database, and all the feed data comes from external feeds that change over time, so unless I fetch it all again, I don’t know.

What I needed was the ability to have a expires_in parameter whilst using FileStore. So this is what the code below does in surprisingly few lines. The code is an amalgamation of many posts I found doing almost the same thing, but this is what works for me.

First we extend FileStore:

# stick this in a file somewhere in your path e.g lib/fs_extend.rb
class ActiveSupport::Cache::FileStore
  def read(name, options = nil) 
    ttl = 0
    ttl = options[:expires_in] if options.is_a?(Hash) && 
                                         options.has_key?(:expires_in)
    fn = real_file_path(name)
 
    return if ttl > 0 && File.exists?(fn) && (File.mtime(fn) < (Time.now - ttl))
    File.open(fn, 'rb') { |f| Marshal.load(f) } rescue nil
  end
end

And then in your controller I have:

class FooController < ApplicationController 
  def do_stuff
    key = 'someuniquekey'
    expire_fragment(key) unless 
        @data = read_fragment(key, :expires_in => 1.hour) || 
                                  write_fragment(key, some_complex_data)
 
    respond_to do |format|
      format.xml
    end 
  end
end

This has reduced many 5 second requests to 32ms requests, so hurrah!

Hurrah, there has been one response to this post.

  1. Jarred Nicholls

    Very nice and straight forward – makes total sense to me. Thanks for sharing.


back to the top