RESTful app design means that the same action can generate both HTML and XML. One problem I’ve encountered is that XML in the form of an RSS or ATOM feed could be page cached, but the HTML version should not be (since it might show flash messages or be customized for authenticated users).
http://peepcode.com/products # => Generates customized HTML http://peepcode.com/products.rss # => Changes infrequently and could be cached
Edge Rails has a nice feature that could possibly be used to cache some formats but not others. In the meantime, here’s an alternate strategy that works for simple sites that need to cache only a few feeds:
after_deploy task could do the caching.A rake task:
desc "Cache specific feeds manually. To be called from cron."
task :cache_feeds do
require 'open-uri'
%w(
products.rss
products.atom
).each do |filename|
unless File.exist?("public/#{filename}")
File.open("public/#{filename}", "w") do |f|
f.write open("http://peepcode.com/#{filename}").read
end
end
end
end
A cron:
@hourly cd my_rails_app/current && rake cache_feeds RAILS_ENV=production
Here’s a sweeper that will delete the cached feeds when content is created or saved.
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
def after_save(record)
expire_page hash_for_formatted_products_path(:format => :rss)
expire_page hash_for_formatted_products_path(:format => :atom)
end
end
To activate, put the following line in the products controller:
class ProductsController < ApplicationController cache_sweeper :product_sweeper, :only => [:create, :update]
HTML content will still be generated dynamically by Rails, but the cached RSS and ATOM versions will be served from disk, reducing load on the server.
I once heard about an approach where the person (technoweenie?) used page and action caching across the entire site, but for stuff that’s user specific he had a session resource that returned the session information in JSON format. A JS library took this and replaced the HTML on the page with user specific information, like the “logged in as” part and the flash messages.
This allowed a consistent caching approach to be used for all the content, while also allowing per-user customization to occur on HTML pages.
What do you think about this approach?
Dan… may be way too obvious, but what about graceful degradation for non-JS surfers? Sounds like that solution pretty much kills your app in that case.
(my apologies to topfunky if I’ve hijacked the blog comments with something a bit off-topic)
Mars, graceful degradation means that an application can still function with less capable user agents, but its understood that the experience may degrade when using those UAs.
I’m not suggesting an application be unusable or disabled for people without JS support, I’m just saying that there are alot of applications where personalization isn’t critical for the application to still function. I would be surprised if non-JS surfers expected all sites to function exactly the same as JS users.
When I design apps I tend not to worry about graceful degredation anyway, and approach it from the opposite end with progressive enhancement: make the application work for lower capability user agents (non-JS, non-CSS, no-images—basically text-only browsers and bots), and add extra functionality for more capable user agents. I find this results in a more usable application on a wider variety of user agents, like screen readers, but still provides the smoother experience for JS/CSS/Cookie enabled browsers.
@Dan: That’s an interesting idea, and I asked technoweenie about it once. The current RailsWeenie seems to run on the Beast Forum, so they must have abandoned that technique.