[uf-rest] RESTifying RAILs

Dan Kubb dan.kubb at autopilotmarketing.com
Fri Nov 4 13:12:51 PST 2005


Hi Ernie,

Q: Is RESTifying Rails OT for this list?  Maybe it would be
better to move this to rest-discuss or the Rails list?

> My only concern is with your mechanism for handling other methods:
> That seems a bit verbose, not to mention non-backward-compatible.   
> I'd prefer something like:

You're right, replacing the way rails dispatches to methods
in the core would probably not be a good idea.  I was more
thinking along the lines of providing a way for us to
dynamically choose the exact method that was dispatched to
within a controller.

>>   GET     /person/123         -> Person.index
>>   POST     /person/123         -> Person.index_POST
>
> That is, the default is GET as usual, but one can suffix a method  
> to indicate a special response.  I also think using ALL CAPS is  
> better to a) avoid collision with normal URIs and b) signal clearly  
> that this is special.  Though, is CAPS in a method name bad Ruby  
> hygiene?

There's something about using CAPS in ruby method
names that offends my sense of aesthetics. ;)

For the dispatched-to method names I still prefer to use
the naming convention "verb_noun" since it tends to read
better For example I prefer delete_item ("Delete the Item"),
rather than item_delete ("Item Delete").  Methods in rails
seem to be named so that when read out loud they read
like a sentence.

To avoid collision with normal URIs you could mark the
method as protected or private.  That would prevent
people from using links like /person/1234/delete_index.

Also to expand on your idea about calling Person.index on
GET:  What if the behavior for the RESTful dispatcher
is to call Person.index ONLY if the corresponding
Person.get_index wasn't available?  Likewise for PUT
requests, it would use Person.index only if Person.put_index
wasn't available.  I think that would be in-line with
standard rails behavior.

> Actually, there might be another way -- automatically insert the  
> necessary JavaScript to synthesize the request from a form:
>
> http://jibbering.com/2002/4/httprequest.html
>
> If we're controlling the generated HTML anyway, why not solve it on  
> the client-side?  This is a browser limitation, so better to fix it  
> there; and if from the designer's point of view it is zero-cost why  
> not pretend to do the right thing?

I thought about using AJAX to solve this problem, but I'm
just not sure I'm ready to require javascript for all
the users of my system.  I guess its a trade-off either
way.

Given the choice I'd prefer to use some sort of standardized
way of tunneling PUT/DELETE/etc over POST, and use AJAX
(when available) to issue real PUT and DELETE commands.
Then once the state of browsers has caught up, I can drop
both of these approaches.

>> anyway, so I figure I'll use a convention to do it.
>
> So, what convention to you use, exactly?  Explicitly specifying a  
> "put_index" URI?

No, there's no placing verbs inside the URI -- I think that's
a big no-no.  URI's are forever, but the representation is
malleable, so thats where I decided to compromise.  I'm using
a simple naming convention within the web form, like so:

   <form method="post" action="/person/123">

     <!-- ... some other fields containing attributes of the  
person ... -->

     <input type="hidden" name="method" value="put" />
     <input type="submit" name="method_put" value="Save" />
     <input type="submit" name="method_delete" value="Delete" />
   </form>

The logic to dispatch is buried inside the controller example
I sent, but its pretty simple:

     def tunneled_method
       allowed_methods.find { |m| params['method_' + m] } || params 
[:method]
     end

The submit button parameter is searched for first, and if not
found the "method" parameter is used to set the form's default
method.  This handles the case where a button is explicitly
pressed or when the user just hits the return key to submit
the form; and it also allows you to label the buttons any way
you wish.

The only case I haven't decided on how to best handle is when a
form is submitted to /person/, but the user clicked on a button
that should result in a DELETE on /person/123.  I'm sure its just
a matter of coming up with a naming convention and then dispatching
to the correct controller/method.

A plus to using naming conventions within the form is that
javascript could be written so that when the appropriate button
is clicked a real PUT and DELETE can be done via AJAX.

Yeah, I realize this is a hack, but it seems to work fine in
practice.  Obviously I would prefer it if the HTML standards
supported methods other than GET and POST, and if nested forms
were allowed; but they aren't yet.  I am of course open to
suggestions if there is a better way.

--

Thanks,

Dan Kubb


More information about the microformats-rest mailing list