• Home
  • About

stonean

Feeds:
Posts
Comments

Dynamic Content and Action Caching

October 3, 2008 by stonean

I recently deployed a Rails application that, for various reasons, required caching dynamic content. All dynamic content is represented by a core “Content” model that contains a url attribute. In order for my app to show these pages I have the following as my last route:

  map.dynamic ':p1',
  :controller => "contents",
  :action => "show",
  :requirements => {:p1 => /[\w|-]*/}

As you can see, the contents/show is my catchall action. If I can find a content url matching :p1, I show the content.

Another feature of the application is that you can restrict access to this content to one or many user groups via my Lockdown gem. At a basic level, Lockdown works by testing for access in a before_filter it adds to all controllers. To ensure I don’t expose protected content, I needed to use action caching to have my before filters execute before showing the page.

Action caching typically creates a cache file that corresponds to the action. However, in this case, the show action represents multiple urls. Here’s how you get around that:

class ContentsController < ApplicationController
  caches_action :show,
    :cache_path => proc{|c| c.send(:cached_page, c.params[:p1], c.params[:page]) }

  def show
   #logic to render multiple content types
  end

  private
  # This method will return my cache name
  def cached_page(url, page)
    page ||= "1"
    "#{url}_#{page}"
  end
end

If the url for the contents was “/about-us”, the cache would be “about-us”. If the content url was “/reunion-pictures?page=2″, the cache would be “reunion-pictures_2″. So forth and so on.

I was going setup a route that would turn “/reunion-pictures?page=2″ to “/reunion-pictures/2″, but for some reason, adding the route to do this broke the display of the page links in will_paginate. I’m not sure why and the url wasn’t that important to me. The value provided by will_paginate was more important to me than pretty routes in this instance. I may revisit this issue later…but I need to get back on point.

So…I’m caching now, cool. Now I just have to account for changing content, enter the sweepers:

class ImageSweeper < ActionController::Caching::Sweeper
  observe Image

  def after_create(post)
    expire_cache_for(post)
  end

  def after_update(post)
    expire_cache_for(post)
  end

  def after_destroy(post)
    expire_cache_for(post)
  end

  private
  def expire_cache_for(record)
    record.galleries.each do |gal|
    for i in 1..((gal.artworks.length / 10) + 1)
      expire_action("#{gal.url}_#{i}")
    end
  end
end

One type of dynamic content is a gallery that can contain multiple images. In order to make sure my galleries are kept up-to-date, I needed this sweeper to expire the caches of the galleries that contained the images I was creating/updating/deleting.

In order for this ImageSweeper to clean house, I needed to add the following to the ImagesController:

  cache_sweeper :image_sweeper,
    :only => [:create, :update, :destroy]

Now my galleries will stay current and I won’t be locked into showing cached galleries that represent old/incorrect information.

The cached pages are ridiculously faster…and yes, that’s a technical term similar to “ludicrous speed”.

Posted in RubyOnRails | No Comments Yet

  • Open Source


    Lockdown (GitHub)
    RuHL (GitHub)

  • Recommend Me

  • twitter: stonean

    • So I submitted my RailsConf proposal, called it Beyond MVC. We shall see. I do such a bad job talking about myself, the bio sucked. 7 hours ago
    • @ubermuda that's good to know, thank you! 1 day ago
    • @chanmix51 cool, thanks! 1 day ago
    • In vi, :set list to show hidden characters, to revert, :set nolist Very handy. 1 day ago
    • Team just did their first PechaKucha [ http://vurl.me/EEP ] session. I love this format and am very impressed with results! 2 days ago
  • Categories

    classy-inheritance Code Style DataMapper Fusion git Haml Interview Questions jQuery lockdown Merb MysqlUtils Process Quick Tips REST RSpec Ruby RubyOnRails rubytrends Stage thoughts Uncategorized


  • Archives

    • November 2009
    • May 2009
    • April 2009
    • March 2009
    • February 2009
    • January 2009
    • December 2008
    • November 2008
    • October 2008
    • August 2008
    • July 2008
    • June 2008
    • May 2008
    • April 2008
    • March 2008
    • February 2008
    • January 2008
    • December 2007
    • November 2007

Blog at WordPress.com.

Theme: Mistylook by Sadish.