Rails Page Caching and Internationalization

How to hack your Rails application to configure how page caches are stored

Rails offers an effective caching solution for caching pages using page_caching. This stores the entire output of a request into a publicly accessible file which is then picked up by the web server first before the request is made to Rails. The Rails default method to set the path of the is something that doesn’t take the locale nor the subdomain into consideration. So if you have a subdomain that is bound to the same Rails server, then the page caching will not append any of that to the name of the cached page file. This blog article will explain how to change this behaviour.

Last Updated

This page was last updated on December 29th 2011 and was first published on May 9th 2012

How (where) Rails stores its page cached files

The page that Rails (up to and including its latest version Rails 3.1) stores its page caches are in /public folder of the project root. This configuration can be configured within the application.rb file by setting the following configuration:

config.action_controller.page_cache_directory = Rails.root.to_s + "/public"

When a caches_page directive is set within a controller for a particular action then the page caching sets up the path of the URL to be the path of the cache file. This can be changed within some function overriding.

How to override it

In your app/controllers/application_controller.rb set the following code to change the way that the file is written. Here is the default:

def self.page_cache_path(path,extension)
  # Default
  MyApp::Application.config.action_controller.page_cache_directory + path + extension
end

Now lets imagine if you were to include the locale into the mix:

def self.page_cache_path(path,extension)
  # Appending the locale
  path += '-' + I18n.locale.to_s

  # /users/1/search will be stored as public/users/1/search-en.html (or without the .html)
  MyApp::Application.config.action_controller.page_cache_directory + path + extension
end

And we can also include the subdomain. Lets imagine that www is the default locale … English (en) and anything else is non-www. The only issue is that the page_cache_path method is a class-level method (static) so the request object won’t be recognized by the class method. We’ll need to add a class variable as a before filter:

before_filter :prepare_subdomain

def prepare_subdomain
  @@subdomain = request.subdomains.first.to_s
end

def self.page_cache_path(path,extension)
  path += '-' + @@subdomain
  MyApp::Application.config.action_controller.page_cache_directory + path + extension
end

Configuring your HTTP Server

So far I’ve only done this with NGINX. What needs to be done is to configure your NGINX server to recognize that the page cached file is there before it fires up the Rails request. Here is my configuration file:

server {
  listen 80;
  server_name ~^(\w+).mydomain.com$;

  set $subdomain $1;

  if (-f $document_root/$uri-$subdomain.html) {
    rewrite (.*) /$1-$subdomain.html break;
  }
}

It will take alot of trial and error with getting NGINX to fully recognize your page cached files. Therefore, its better to install NGINX locally and change the HOSTS configuration a proper domain to point on your computer and perfect it that way. Keep in mind that NGINX does not allow AND and OR pre-conditions or nested if statements so you’ll need to use concatenation and variable checking to get something complex to work.

One Response to “Rails Page Caching and Internationalization”

Add Your Comment