Page Caching by Subdomain in Rails and Nginx

Posted By Ryan Stout on July 30, 2010

I'm internationalizing an app, and am splitting the locales by subdomain (es.bustaname.com, fr.bustaname.com, etc...) While other people have solved the page_caching issue with subdomains before, I couldn't find a clear explanation. All of the examples were missing one piece of information.

Controller

Add the following into your controller.

class ApplicationController < ActionController::Base
  # Cache pages with the subdomain
  def cache_page(content = nil, options = nil)
    path = "/#{request.host}/"
    path << case options
    when Hash
      url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format]))
    when String
      options
    else
      if request.path.empty? || request.path == '/'
        '/index'
      else
        request.path
      end
    end
    super(content, path)
  end
end

This will cache each subdomain in its own directory.

To keep things clean I also move my cache directory into public/cache Just add the following to your environment.rb inside of the run block.

Rails::Initializer.run do |config|
	config.action_controller.page_cache_directory = RAILS_ROOT + '/public/cache/'
end

Then the part everyone else seemed to miss is that this will make something like caches_page :index (note the pluralization) work, even though we defined a cache_page method. ActionController::Base has both a class and an instance version of cache_page and a class method called cache_pages. You want to use the class method cache_pages.

Nginx

Next place the following in your nginx.conf file:

# If the file exists in the public folder, send it
if (-f $request_filename) {
  break;
}

# Check / files with index.html
if (-f $document_root/cache/$host/$uri/index.html) {
  rewrite (.*) /cache/$host/$1/index.html break;
}

# Check the path + .html
if (-f $document_root/cache/$host/$uri.html) {
  rewrite (.*) /cache/$host/$1.html break;
}

# Check directly
if (-f $document_root/cache/$host/$uri) {
  rewrite (.*) /cache/$host/$1 break;
}

This will look up cached files in /cache/$host/ and should send the files correctly. Be sure to add the nginx config before you send it to mongrel/thin/etc..


Tags: rails, caching, subdomain, cache_page, nginx

Showing 6 comments

twitter followers Posted 6 months ago

Appreciating the time and effort you put into your blog and detailed information you offer. It's great to come across a blog every once in a while that isn't the same unwanted rehashed material. Excellent read! I've bookmarked your site and I'm including your RSS feeds to my Google account.

lulalala Posted almost 2 years ago

Thanks for the post. I am just wondering if you made a type: caches_page ==> cache_pages

Jason Posted over 2 years ago

Great post! Any thoughts on how this might work on heroku? http://stackoverflow.com/questions/8304166

Darek Posted over 2 years ago

Thanks for the post - great and condensed work!

Richard Posted almost 3 years ago

Hi Ryan, I'm on my latest project to build at about 10 of subdomain for any topic's. Each of them need cache directory's. I created a custom rss for each of them too. My question is, "How to make them all only using 1 cache directory? Is that possibly? How to make it possibly with PHP?" Could you please advice me to my email. I really appreciated for that. I'm looking forward to hearing from you. regards, Richard Daris http://www.uni.street.co.id

Saravana Posted over 3 years ago

Thanks for the post Ryan. I had disabled sub-domain support in my website (www.kettik.com) till i had figured out how to handle page caching for the subdomains. Your post has given me a good starting point. Btw, 1 question... how do you handle the case when 'www' is given in the hostname.

Post a Comment