RESTy Routes in Rails

Drinking DHH's KoolAid

Theodore Polonsky Presented to Rubyists of Second Life August 31, 2006

Corrections

Jesse Malthus: and so, I'll turn the floor over to Theo!
Theodore Polonsky: grins
Theodore Polonsky: Thanks Jesse
Theodore Polonsky: First, I've never done a formal presentation in SL before, so this is experimental for me
Theodore Polonsky: Second, I swiped a lot of these slides from DHH's talk at RailsConf
Theodore Polonsky: So....if you haven't seen his presentation, please do so after this...it was a great talk
Theodore Polonsky: So, we'll be talking about two words: REST and CRUD
Theodore Polonsky: What they mean, how they relate to Rails, and why, for me at least, this is such a big deal
Theodore Polonsky: I cut down the number of slides so they'd all rez, but if you can't see one, just yell and I'll wait...or, post them later
Theodore Polonsky: Here's a quote from the guy who identified REST as a pattern...it's long and complicated
Theodore Polonsky: But basiclally, REST stands for REpresentational State Transfer
Theodore Polonsky: What it REALLY means is, make your webapps act like WEB apps, not something else
Theodore Polonsky: Roy wrote about this for a PHd dissertation which is why he used so many more words to say that
Theodore Polonsky: So what is a resource?
StarJunky Fermi: guffaws
Theodore Polonsky: It's just a URL, really
Jack Moseley: dot sl? must reg..
Theodore Polonsky: grins
Theodore Polonsky: I think it's Sierra Leone....:)
Jack Moseley: wishes himself luck then
Theodore Polonsky: But whenever we talk about resources, just think about things you find on the web
Theodore Polonsky: The other important bit is Representational....a representation of a resource
Theodore Polonsky: So, when you download a URL in Safari, you get an HTML representation of it
Theodore Polonsky: Or XML
Theodore Polonsky: Or JS
Theodore Polonsky: etcetc
Theodore Polonsky: Has that slide rezzed yet?
Jesse Malthus: yeah
Simon Pulford: sorry., brb
Jesse Malthus: if it hasn't, just hover over the board
Theodore Polonsky: So you see that the resource we downloaded gave us an XML representation of me
Theodore Polonsky: Here's the other word...and I'll tie them together ina minute
Theodore Polonsky: CRUD
Theodore Polonsky: Create
Theodore Polonsky: Read
Theodore Polonsky: Update
Theodore Polonsky: Delete
Theodore Polonsky: As DHH said: Boring
Theodore Polonsky: Right?
Jesse Malthus: right
Theodore Polonsky: Rails scaffolds give you this for free
Theodore Polonsky: It's the basic stuff
Theodore Polonsky: Not where real apps are made
Theodore Polonsky: ...
Theodore Polonsky: Standard Rails controller actions...if you've done a Rails tutorial you know them
Jack Moseley: I think if you just focus the camera on the slide it'll rez quicker..
Theodore Polonsky: And they actually map really closely to SQL commands:
Theodore Polonsky: find create update destroy
Theodore Polonsky: SELECT INSERT UPDATE DELETE
Theodore Polonsky: So here's where the major Rails CRUD/REST abstraction happens...
Theodore Polonsky: they also match up to the 4 HTTP verbs
Theodore Polonsky: GET POST PUT DELETE
Theodore Polonsky: When DHH put that slide up, I went, Duh.
Theodore Polonsky: Of course they do
Theodore Polonsky: How could we all have been so blind!
Theodore Polonsky: :)
Theodore Polonsky: So, let's look at the standard Rails routes again fr a second
Britt Spear: Why does put == post?
Jack Moseley: (its cause no one ever uses PUT/DELETE)
Jesse Malthus: put != post
Theodore Polonsky: I'll answer PUT POST in a second...but, there is some controversy there :)
Theodore Polonsky: Anyway
Britt Spear: Thanks
Theodore Polonsky: Look at these routes....there's dedundancy
Theodore Polonsky: remind me if i forget, Britt
Theodore Polonsky: redundancy, too
Theodore Polonsky: and redundancy
Theodore Polonsky: We're posting to /people/create
Theodore Polonsky: 2 verbs there, POST and create
Theodore Polonsky: We're getting, and saying show....GET and show
Theodore Polonsky: So, what if we instead did this
Theodore Polonsky: POST to the collection to create
Theodore Polonsky: GET the resource to show
Theodore Polonsky: PUT to the resource to update
Theodore Polonsky: DELETE to the resource to delete
Theodore Polonsky: Anyone ready to yell about browsers not supporting PUT and DELETE yet? ;)
Jesse Malthus: mememe!
Jack Moseley: I was going to say that PUT is a horrible verb
Theodore Polonsky: It's covered :)
Jack Moseley: the rest work much better
Theodore Polonsky: Yes, POSTing to the resource is (and may by now) considered by some better
Theodore Polonsky: I think they're editing that
Theodore Polonsky: Anyway, simply_restful is a plugin for Rails 1.1.6 (you ARE running 1.1.6 by now, right?) ...
Jesse Malthus: of course!
Theodore Polonsky: that adds routes like these that map to the standard controller actions
Jesse Malthus: runs off to check
Theodore Polonsky: And it uses a single command in the routes file to generate them all for that resource
Jesse Malthus: wow
Theodore Polonsky: So a GET to the resource maps to a different action than a PUT/POST or a DELET
Polypus Watts: that's nice!
Theodore Polonsky: and it makes named URLs for you, too, like person_url(@person)
Jesse Malthus: I like routes alot ^_^
Theodore Polonsky: people_url
Theodore Polonsky: new_person_url
Theodore Polonsky: etc
Theodore Polonsky: and those call the standard actions
Theodore Polonsky: create show update and destroy
Theodore Polonsky: CSUD?
Theodore Polonsky: laughs
Jack Moseley: CUS(S)'D
Theodore Polonsky: but we're missing 1 little bit...how do you get the form to edit a person?
Baboo Vogel: or SCUD if you prefer
Theodore Polonsky: A GET on the resource gives the resource itself...but not the edit form
Jack Moseley: A get on the put?
Jack Moseley: haha
Theodore Polonsky: So someone dragged way back in the HTML spec and discovered that Tim Berners-Lee had thought ahead
Theodore Polonsky: using semi-colons for "aspects" of a resource
Jesse Malthus: woah
Jack Moseley: Oh wow, I never knew that was actually part of the standard..
Theodore Polonsky: so a GET to /people;new Is the "New person" form
Jesse Malthus: thanks TBL!
Polypus Watts: that's fresh!
Theodore Polonsky: and /people/42;edit says, "Give me person 42, but in edit mode"
Theodore Polonsky: so simply_restful defines those 2 routes too
Theodore Polonsky: all from 1 line of config
Theodore Polonsky: and a basicly boring controller
Theodore Polonsky: So, it's also in Rails Core now, and they made a few changes....tiny ones that rock
Theodore Polonsky: It's map.resources, and takes multiple args
Theodore Polonsky: AND
Theodore Polonsky: you can nest them
Theodore Polonsky: So in this case, we'd get URLs like /people/42/hats/1
Jesse Malthus: /person/42/hats/1?
Theodore Polonsky: For my Hat number 1
Jesse Malthus: jinx!
Theodore Polonsky: and /people/42/shoes/new
Theodore Polonsky: owe you a coke :)
Theodore Polonsky: So you scope your controllers to the collection they belong to, without any modules or nastiness like that
Theodore Polonsky: That right there changed the way I write Rails apps, completely
Theodore Polonsky: So, What good is it? Why di I care?
Theodore Polonsky: It's clean...the controllers get really boring and easy to maintain
Theodore Polonsky: It's easy....because you can usually copy-paste a RESTy controller to start a new one, change the names, and it Works
Theodore Polonsky: (until you add scopes and permissions and stuff)
Theodore Polonsky: And it's discoverable...which I'll explain in a minute
Theodore Polonsky: Scott Raymond refactored IconBuffet into restful routes
Theodore Polonsky: He went from 10 controllers with 76 (!) actions
Theodore Polonsky: to thirteen controllers and only 58 actions
Theodore Polonsky: got a better handle on his domain model
Theodore Polonsky: dropped lots of moving parts
Theodore Polonsky: and made it easier to understand and maintain
Theodore Polonsky: here's a quote
Theodore Polonsky: I'll let it rez and you read while I rest a second
Theodore Polonsky: and then i have 2 other cool things to sshow real quick
Theodore Polonsky: there's a common thread, though...RESTful routes eliminate redundancy in URLs and in code
Theodore Polonsky: Ready?
StarJunky Fermi: you betcha
Theodore Polonsky: So
Theodore Polonsky: 1 action
Theodore Polonsky: in 1 controller
Theodore Polonsky: many formats?
Theodore Polonsky: If you access /people/42 or /people/42.html you get the HTML representation
Theodore Polonsky: If you access /people/42.xml you get XML
Theodore Polonsky: /people/42.js you get JS for AJAX apps
Theodore Polonsky: from 1 action
Theodore Polonsky: So no duplicate code, and you basicaly get an XML api for free
Theodore Polonsky: You'll see this pattern a lot in RESTy Rails apps
Theodore Polonsky: Remember I said discoverable?
StarJunky Fermi: very DRY!
Theodore Polonsky: At this point in DHH's talk I had chills. I knew what he was going to show right before he clicked the slide
Theodore Polonsky: Ys very very DRY
Theodore Polonsky: ActiveResource
Theodore Polonsky: It''s in the trunk now
Theodore Polonsky: Beta
Jesse Malthus: O.O
Theodore Polonsky: If you use these conventions, you basically get an API client for free, too.
Jesse Malthus: ^_^
Theodore Polonsky: Point ActiveResource at the web server, and then treat them like local objects
Jesse Malthus: swoons
Theodore Polonsky: Seriously.
Theodore Polonsky: I'm all excited just talking about it.
Andy Driggs: That is great!
Theodore Polonsky: PUT and DELETE! Until browsers support it we're hacking it with a hidden form param, _method => :put
Jacek Antonelli: I'm all excited listening to you talk about it, and I don't even know half of what you are saying! (Not a web programmer)
Theodore Polonsky: It sucks. Anyone who knows a browser manufacturer, yell at them for decent PUT and DELETE support
Theodore Polonsky: Until then it's a hack and no one likes it but it works
Jesse Malthus: Firefox should get it soon, right?
Theodore Polonsky: ;edit isn;t a hack, it's beeyoootiful
Theodore Polonsky: And you can add your own ;aspect methods
Jesse Malthus: but _method is
Theodore Polonsky: Yeah, _method is nasty and no one disputes it
Theodore Polonsky: Some URLs to copy down....I should have called this slide resources
Theodore Polonsky: Any questions?
StarJunky Fermi: Does Rails REST have anything to say about saving client session state on the server?
Theodore Polonsky: Sorta
Theodore Polonsky: Some people are going all out and saying EVERYTHING is REST
Theodore Polonsky: so, for auth you post to /sessions/new
Theodore Polonsky: logout is /session/43 (DELETE)
Theodore Polonsky: I think that's nuts, but I may drink more KoolAid later
Theodore Polonsky: Is that what you meant?
StarJunky Fermi: yes - I'm guilty of storing all kindsa client session info on the server
Theodore Polonsky: That's probably OK, really
Theodore Polonsky: To make a rich app
Jesse Malthus: I like my session hash!
Theodore Polonsky: As long as your resources still act like resources
Theodore Polonsky: /people/42.xml should always be the same thing :)
Theodore Polonsky: It's me, in XML
StarJunky Fermi: ok - so its really how you craft your actions and resources
Theodore Polonsky: Yes, it's about tying your domain model and your controllers closer together
Jesse Malthus: I have a small question: what's with the :credentials thing in AcriveResourse
Theodore Polonsky: Ah, it allows you to pass in authentication
Theodore Polonsky: So you set that on the Class, and then just treat it local
Theodore Polonsky: HTTP AUTH, of course ;)
Jesse Malthus: ah
Jesse Malthus: I was about to ask how authentication is done by REST
Theodore Polonsky: TBL and Roy Fielding would say it's built into the Spec
Jesse Malthus: but I supose since HTTP is doing most of the verbage, that HTTP AUTH is best
Theodore Polonsky: HTTP supports auth right there :)
Theodore Polonsky: But, many of the login plugins for Rails now support both HTTP AUTH and Forms
Theodore Polonsky: For APIs you'd just use HTTP probably
Theodore Polonsky: Anything else?
StarJunky Fermi: Great presentation Theo!
Theodore Polonsky: PUT vs POST
Polypus Watts: here here
Theodore Polonsky: There's some debate about that the spec says about those
Ray Varun: Well done!
Theodore Polonsky: DHH wanted 4 verbs, so he used PUT
Hoodoo Guru: great job
Baboo Vogel: will ActiveResource have bindings other than for HTTP?
Theodore Polonsky: POST creates new one, PUT changes existing one
Jesse Malthus: ah
Theodore Polonsky: But i think a POST to an existing resource is valid
Hoodoo Guru: you need to post screen of this to your blog...
Jesse Malthus: I think that's kinda ugly.
Jesse Malthus: I'd rather have CHANGE, but that's not in the spec
Theodore Polonsky: So I suspect those routes will handle PUT or POST
Jack Moseley: Whats the word on firefox supporting the extra verbs?
Theodore Polonsky: I like PUT myself..."Put this representation (XML doc) at this resource"
Theodore Polonsky: just like PUT in FTP
Jack Moseley: in ftp
Jack Moseley: put creates a new file.
Alysn Eponym: Except that put also creates a new file, as well as replace one.
Theodore Polonsky: Baboo, I doubt ActiveResource will ever be non HTTP
Theodore Polonsky: nods
Theodore Polonsky: Exactly :)
Theodore Polonsky: I don't know what the HTTP spec really says the difference is, to be honest
Jack Moseley: yea, if you think of it as REPLACE rather than EDIT/UPDATE
Theodore Polonsky: OK? All set?
Theodore Polonsky: Thanks for coming everyone, this was fun :)
Alysn Eponym: That's a good point. We can assume Put will replace a portion of a record and not just the whole thing, right?
Jesse Malthus: yeye Theo!
Adam Marker: thanks; well done!
Theodore Polonsky: Jesse, back to you
StarJunky Fermi: Thank YOU
John Otafuku: Thanks!
Polypus Watts: thanks theo nice demo
Jesse Malthus: thanks a ton
Baboo Vogel: thanks, it was very helpful
Theodore Polonsky: Alysn, depends on the controller, but yes it should
Alysn Eponym: Excellent presentation! Thanks!
Alysn Eponym: And whoever posted the notice on Ruby-talk... Thanks ;)
Simon Pulford: thks!!
Theodore Polonsky: laughs
Jesse Malthus: :D that's Theo
Ray Varun: Aye, thanks for having us!
Alysn Eponym: Good man!
Andy Driggs: Thanks Theo!!!
Jesse Malthus: I have not the time to read and post to ruby-talk ^_^
Theodore Polonsky: I had the time to post....
Theodore Polonsky: laughs

Corrections

I said Simply Restful was available for 1.1.6, but it isn't. Here's a backport.