What's New in Edge Rails: Even Better Conditional GET Support

Posted by ryan
at 9:13 PM on Friday, October 24, 2008

This feature was released in Rails v2.2.1

We talked about the new conditional GET support in rails a couple months ago. As some of the comments alluded, the feature was somewhat cumbersome to use – especially by Ruby standards. Well, the feature has since been refined. So, read the original post to get the gist and come back here for the sugar.

Instead of manually setting properties directly on the response and querying the request to see if it’s fresh we have some higher-level accessors we can use. Observe (extending our previous example):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ArticlesController < ApplicationController

  def show
    @article = Article.find(params[:id])

    # If the request is stale according to the given timestamp and etag value
    # (i.e. it needs to be processed again) then execute this block
    if stale?(:last_modified => @article.published_at.utc, :etag => @article)
      respond_to do |wants|
        # ... normal response processing
      end
    end

    # If the request is fresh (i.e. it's not modified) then you don't need to do
    # anything. The default render checks for this using the parameters
    # used in the previous call to stale? and will automatically send a
    # :not_modified.  So that's it, you're done.
end

If you don’t have any special response processing and are using the default rendering mechanism (i.e. you’re not using respond_to or calling render yourself) then you’ve got an easy helper in fresh_when:

1
2
3
4
5
6
7
8
9
class ArticlesController < ApplicationController

  # This will automatically send back a :not_modified if the request is fresh, and
  # will render the default template (article.*) if it's stale.
  def show
    @article = Article.find(params[:id])
    fresh_when :last_modified => @article.published_at.utc, :etag => @article
  end
end

There you have it, the new and improved conditional GET support in Rails 2.2.

tags: ruby, rubyonrails

Comments

Leave a response

  1. JinzhuOctober 25, 2008 @ 03:53 AM

    Great Stuff.

  2. SebastianOctober 25, 2008 @ 04:23 AM

    How would you combine this with page- or fragmenting caching? Does it even make sense to cache inside an etag-block?

  3. James StewartOctober 25, 2008 @ 05:00 AM

    @Sebastian – I’m using this with the caching inside the block.

    In most of my code I grab an initial object from the database which I use to check if anything has changed. I then have other code within the block that uses caching.

    It makes sense to do that as the etag/last-modified support is per-user whereas you may want to use caching to grab content regardless of the user.

  4. EvenskyNovember 01, 2008 @ 03:37 AM

    hello can I talk to u on my mail Ryan i’m Anthony casseus cousin…

  5. PeterNovember 03, 2008 @ 07:16 PM

    Very interesting , but @James if you hit your database first what’s the purpose of caching?

    And how can we benefit more using this technique if we need to hit the database first? I know access will be faster since the browser will render the cached version, but you still hitting the DB.

    Thanks,

    Peter.

  6. carlos@webbynodeNovember 06, 2008 @ 04:12 PM

    Good one. Are they breaking anything, as scaffold got broken with one of the late releases?

  7. lomakinNovember 07, 2008 @ 10:22 AM

    Thanks.

  8. jeroen houbenNovember 21, 2008 @ 03:42 AM

    @peter: hitting the database isn’t the only the thing taking up time. Rendering the view may be even more expensive, but now you have a way of skipping that.