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.