Caching without extra parameters

After coming up with a nice solution to the problem of caching based upon subdomain keys, we got negative feedback from our first customer. They said the URLs made them feel like a number, and of course, they were right. Here’s how we solved the problem without putting the website_id in the url:

To summarize, we are trying to allow caching of a site where the content varies based upon the url. We use the URL to find a Website object based upon domain. If you remember correctly, our last solution was to use:

  def default_url_options(options)
    {:website_id=>@website.id} if @website
  end

This puts the website_id in every url, which we then cleaned up with a custom route. Our new solution is much cleaner from a web perspective, but it required making some changes to apache rewrite rules. Our new solution is just to change the caching strategy. Instead of putting cached files directly in the /public directory, we will put them in /public/domain/. From the rails side, the solution is trivial:

    self.page_cache_directory=RAILS_ROOT+File::SEPARATOR+"public"+ 
       File::SEPARATOR+@website.subdomain if @website

We just had to stick that at the end of the method that looks up the website. Basically, we just overwrite the root directory for the caching system to include the domain. Once that was done, we needed to tell apache where to find cached files. This part got ugly!

  # Grab the subdomain
  RewriteCond %{HTTP_HOST} ^([^\.]+)\..*$ [NC]
  # If there isn't a cached file
  RewriteCond %{DOCUMENT_ROOT}/%1/%{REQUEST_FILENAME}.html !-f
  # and there isn't a static file like an image
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  # send it on to rails
  RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

  # grab the domain again
  RewriteCond %{HTTP_HOST} ^([^\.]+)\..*$ [NC]
  # if there isn't a static file
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  # and there is a cached file
  RewriteCond %{DOCUMENT_ROOT}/%1/%{REQUEST_FILENAME}.html -f
  # use the cached file
  RewriteRule ^([^.]+)$ /%1$1.html [QSA,C]

  # otherwise, the fallthrough uses the static file

While that isn’t the most beautiful thing in the world, it works really well for us. Cleaning the cache is incredibly easy, as we can just purge the whole cache directory for a website any time anything in that website changes.

So after a little tweaking, we now have a solution that leaves us with pretty URLs and easy cache clearing while still giving us great performance.

Posted by Mike Mangino on Tuesday, October 10, 2006