Cache it all

I recently redid my personal web site, at welton.it. Wanting to be quick about it, and make the look and feel a bit more uniform than it has been in the past, I hacked together some pages in Rails. Despite this being sort of a “killing a fly with a bazooka” situation, I’ve been doing lots with Rails, so it was quick to use. Here’s the thing, though: Rails is definitely overkill, as the site is basically static. I don’t need to calculate anything or fetch stuff from a database – I just wanted a reasonably good template system, and I am quite comfortable with Rails these days.

But the idea of leaving Rails running for a static site was of course no good: I basically need to cache the entire thing, so that Rails is simply not involved. How to do this as quick as possible (in between diaper changing and other baby duties!) ? Ideally, it would be possible to introspect Rails in order to know exactly which pages are present, then cache those, and avoid Rails on the server entirely (just generate them locally and put them in subversion), but that proved to be fairly hacky, so I settled for this code, which simply caches all pages which comes across, when caches_pages is placed in application.rb:

class CacheFileName
  include ActionController::Caching::Pages
  include ActionController::Caching::Pages::ClassMethods

  def cachedname(path)
    page_cache_file(path)
  end
end

def caches_pages()
  return unless perform_caching
  after_filter do |c|
    res = c.cache_page
    cfn = CacheFileName.new
    cf = Cachedfile.new :filename => cfn.cachedname(c.request.path)
    cf.save!
  end
end

It simply caches everything. To be able to easily clear out the cache if there are any changes to the site, we record the changes in the Cachedfile model, which is defined like this:

create_table "cachedfiles", :force => true do |t|
  t.string   "filename"
  t.datetime "created_at"
  t.datetime "updated_at"
end

with this model:

class Cachedfile < ActiveRecord::Base

  def Cachedfile.clean_cache
    Cachedfile.find(:all).each do |cf|
      begin
        fn = ActionController::Base.page_cache_directory + cf.filename
        File.delete fn
      rescue => e
        logger.error "Error deleting #{fn}: #{e.inspect}"
      ensure
        cf.destroy
      end
    end
  end

end

which has a class method to go through and clean out all the cached files. I call it manually from ./script/clean_cache:

#!/usr/bin/env ruby

ENV['RAILS_ENV'] = ARGV.first || ENV['RAILS_ENV'] || 'development'

require File.dirname(__FILE__) + '/../config/boot'
require "#{RAILS_ROOT}/config/environment"
require 'console_app'

Cachedfile.clean_cache

It’s not a beautiful system, but it gets the job done.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s