Ruby On Rails caching, part 2

Posted by ryan
at 4:36 PM on Thursday, October 06, 2005

It’s pretty obvious what phase I’m at with my app given my recent postings: that’s right, figuring out an appropriate caching strategy.

It seems as though I’ve run across another nuance with caching – if you use the “caches_page” method in your controller for an action that is invoked via XMLHttpRequest (i.e. via AJAX), it won’t get cached. For instance, building on my last issue:

class UsersController < ApplicationController

  caches_page :find, <b>find_simple</b>

  def find
    @user = User.find(params[:id)
  end

  <b>def find_simple
    @user = User.find(params[:id])
    render(:action => 'find', :layout => false)    
  end</b>

end

The “find_simple” method is the action that will be invoked via AJAX and, despite the caches_page directive, it does not get cached. A look at the logs reveals this, as does a look at the cache directory on your filesystem (there will be no users/find_simple/id.html).

The solution is pretty simple, use “caches_action” instead of “caches_page”:

class UsersController < ApplicationController

  caches_page :find
  <b>caches_action :find_simple</b>

  def find
    @user = User.find(params[:id)
  end

  def find_simple
    @user = User.find(params[:id])
    render(:action => 'find', :layout => false)    
  end

end

The ramification of this switch is that now all your action filters will get executed for every request. However, as AJAX calls are usually pretty lightweight, action caching should be quite sufficient.

I know the “caches_page” method adds an ‘after’ filter to the controller for each of its actions – this issue seems to imply that the filter is bypassed when a request comes in via XMLHttpRequest. It would also imply that the app server/RoR knows the difference between a ‘normal’ request and an XMLHttpRequest one – which is not what I would have expected. Anyway, no skin off my back as the solution is quite reasonable.

Comments

Leave a response

  1. John TirsenMay 10, 2006 @ 08:22 PM
    The reason the caching doesn't work is that Ajax requests by default happen with POST. POSTs don't get cached. In prototype use the option {method: get} like this: bq. new Ajax.Updater(url, id, {method: get});