[uf-rest] RESTifying RAILs

David Heinemeier Hansson david at loudthinking.com
Thu Nov 10 03:39:12 PST 2005


> This browser_cache method doesn't look to offer much more
> than what can already be done via expires_in; which requires
> a bit more knowledge of Cache-Control.  There's got to be
> an easier way.  What about something like:
>
> class WeblogController < RestController
>   verbs_for :index do
>     cache_resource :person, :as => :public, :for =>  
> 10.minutes, :only => :get
>
>     def get
>       @person = Person.new(params[:id])
>     end
>   end
> end
>
> The cache_resource method could look at whatever object is
> within @person and inspect its updated_at/lock_version
> attributes to set the outgoing Last-Modified and ETag headers.
> It could also set the Cache-Control and Expires headers.
> Of course, with the :only => :get command we'd restrict this
> to happening only for GET requests.

You're right, browser_cache is too far removed from the action.

However, I'm not entirely comfortable with cache_resource referencing  
a instance variable that'll appear in the method using just a symbol.  
It feel like cause and effect is a tad too separated.

But more importantly, I reckon that lots of pages won't rely simply  
on a single resource to compute whether they're stale or not. At  
least that's not the use model I've been finding to be true.

So perhaps your first inclination was right.

class WeblogController < RestController
   verbs_for :index do
     def get
       @person = Person.new(params[:id])
       render :modified_at => @person.updated_at
     end
   end
end

This would by default just produce a :etag based on the :modified_at,  
but you would also be allowed to set that explicitly ala:

   render :modified_at => @person.updated_at, :etag =>  
@person.lock_version

Because then we could use better composite models ala:

class WeblogController < RestController
   verbs_for :index do
     def get
       @posts    = Post.find(:all, :order => "updated_at")
       @comments = Comments.find(:all, :order => "updated_at")
       render :modified_at =>
         @posts.first.updated_at > @comments.first.updated_at ?
            @posts.first.updated_at : @comments.first.updated_at
     end
   end
end

Or something less contrived, but you get the drift. Lots of pages are  
not bound to merely 1 model. Being a little more explicit opens it up  
to wider usage, me thinks.

> Incidentally, I've implemented a working Rails controller
> that inherits from ActionController::Base that uses the
> "verbs_for" syntax you mentioned at the beginning of
> Round 2.  It handles true conditional GET requests and
> OPTIONS methods.  Conditional PUT works too, which
> allows a web service/AJAX client to get around the whole
> "stale update" problem.

Awesome. Can't wait to see that!
--
David Heinemeier Hansson
http://www.37signals.com    -- Basecamp, Backpack, Writeboard, Tada
http://www.loudthinking.com -- Broadcasting Brain
http://www.rubyonrails.com  -- Web-application framework




More information about the microformats-rest mailing list