Advanced Rails Studio Notes: Day 1

Lovely start to the day. 2 miles from the hotel, my Prius breaks down and won’t start. WTF?! FAIL! Oddly, 30 minutes later (after perusing the sample app that we’re going to discuss during the class), the car starts again with a warning light. During the class, I’m fucking Grand Central Station: my cell phone rang 4 times before lunch. Again, WTF? I’m not a popular guy. Yeesh!

Hehehe… and Twitter went down just before lunch. Sometimes it’s nice to remember that I’m not the only one who is living in interesting times.

Regarding my notes, it’s worth mentioning that I’ve done a bit of Rails 1.2.x development but haven’t touched Rails 2.x until today. That said, as of this morning, I was comfortable with the theory of REST but not the Rails implementation.

Anyhoo, my notes from Day 1 of the class follow after the jump.

  • Session controllers to handle logins evidentally not uncommon.
  • Familiar from J2EE web app design.
    • Mildly surprised as that

Routing (cool — always felt a little clueless about routing) (Mike)

  • map.connect ‘:controller/:action/:id’
  • :controller and :action are just plain ol’ params; just used by the dispatcher to route the request
  • Can put default values in the routes (i.e., foo/show could default to FooController.show(:id => 1))
  • SPLAT tags:
    • map.connect(‘tag/*tags’, …. ) is valid for http://foobar.com/tag/foo/bar/blech/bla
    • results in params[:tags] => [“foo”, “bar”, “blech, “bla”]
    • Handy for default actions to handle 404s
  • map.show_event ‘event/:id’, :controller => ‘events’, :action => ‘show’, :id => 1
    • Results in:
      • showeventurl (good for externalization — absolute)
      • showeventpath (relative)
    • Mildly annoyed that there are still more conventions that I don’t know. At times, the Rails API sets off my Java-ridiculously-thick-API alert.
  • Chad is walking us through ActionPack
    • actionpack gem has ActionController::Dispatcher
      • Dispatcher#dispatch calls handlerequest which calls Routing.recognize(request)
      • named routes work off of methodmissing. Cute.
      • Creates an anonymous Module and removes all of the methods
      • defineurlhelper and a few other methods define all of the methods on the anonymous Module
      • named routes are mixed into views and controllers in routing.rb’s #install (neato)
      • Grateful for this’ lil TextMate bundle o’ joy for popping up gem source.
    • Code is (surprisingly) pretty clean

Break

Had a cool conversation about using subcontrollers — although the routing was painful. Suggested dynamically generating the routing at runtime for each “subsite”. Wonder if loading that would require a Rails monkey patch? SEP.

REST (Dave)

  • Dave is explaining the basics. I wonder how many ppl in the room already know this stuff and are just nodding their heads.
  • If request structure is predictable, simplifies caching
  • Fielding REST thesis: Everyone has read this but me, right?
  • ‘The HTTP verb is “fighting” the action verb in the Rails controller’ — Dave Thomas
  • Someone else mentioned my problem: mixing up PUT and POST
    • Mike: “PUT has a ‘U’ in it. So does update”. That will help me.
  • Good question about “How hard to try to be ‘pure’ in the use of REST” (i.e., avoiding an RPC-like API)
    • DT’s Pragmatic™ ;) opinion: rich user interfaces make REST complex; however, REST is a good fit for back ends and services. Makes sense.
    • DT compares REST to dynamic programming and WSDL/SOAP to static programming. REST requires a ‘leap of faith’ that you can handle whatever comes back.

RESTful Rails Conventions (Chad)

  • Describing some of my pain: Rails 2.0 rewrites a good chunk of what I learned from when I was using Rails 1.2.x.
  • map.resources just creates a bunch of named resources (resources.rb in ActionPack)
  • Someone asks what happens if you don’t want to support “destroy”
    • Deleting the action will result in a 404 — which means that the resource DNE. FAIL
    • Someone pips up that the correct code is 405 (method not supported)
    • Worth doing? I suppose it depends on what you know about your users; will the calling service handle 404 and 405 differently?
    • URIs are created for things like ‘formfor @event’ internally with something like @event.class.name.tolower.pluralize + “uri” to get the eventurl method name and call it.
    • Someone asks ‘What about with formtag’? Chad: doesn’t work with REST. We’ll cover it in a later section of the class.
    • formfor, with an existing id, hacks a hidden
      in indicating that the method would be a PUT. It’s actually accomplished via a POST; browsers don’t support PUT (didn’t know that one…).
      • The _method hack is recognized somewhere in the routing layer. Ick….
    • Rails does actually recognize a real PUT request as well for non-browser clients
    • RESTful destroy: don’t forget that :method is an HTML option… so :method => :destroy
  • RESTful routing:
    • map.resources :events, :collection => { :search => :get }, :member => { :copy => :post }
    • maps to http://foo.com/events/search?….
    • maps to http://foo.com/events/123/copy?….
    • Rails doesn’t cache the request parameters — therefore something like http://localhost:3000/events/search?term=foo isn’t idempotent so may not be truly RESTful (Note to self: look into this more later)
    • Great discussion ensuing over whether this is really RESTful or not.
    • Dave said that maybe he’d write a search controller
    • I pointed out that the above URL could just be /events/search/foo as a custom route addressing EventsController#search and then, *voila* RESTful. Chad thought the same thing.
    • DT: don’t use this as something to beat yourself with. It’s supposed to make your life easier.
    • Could just reuse an existing action that uses a parameter — if the view is essentially the same.
    • Chad just tried the idea that we both had; it doesn’t work with map.resources. DOH!
      • What about with just creating our own named resource? If map.resources is just generating a named route, we should be able to do the same thing.
      • Doesn’t consider the HTTP method per Chad. Fuck.
      • Where is the ued HTTP method checked? Hrm…..

Lunch

  • Andrew Willis, from CustomInk, mentioned that they use Pen for their load balancer. It queues up the requests itself rather than queuing them up on the Mongrels. Plus the load balancing algorithm is configurable. Sounds handy.
  • Good discussion at lunch about whether JRuby will become the preferred deployment environment for Rails by the end of the year. I have a hard time buying that until a language spec is agreed upon.
  • Dammit, not enough time to do the labs. Too busy talking about Ruby/Rails at lunch.

Handling RESTful Requests in Rails

  • xml simple gem makes it easy to go to/from hash/XML
  • #toxml, #toyaml (#to_json)
  • Set the HTTP accept header OR put a “.xml”. Either works. Motherhood and apple pie so far.
  • Ah, now #respondto
    • Some, including DT, complain about respondto living in the controller layer; it’s presentation related, really. Agreed. It’s largely irrelevant to the behavior but may effect the content of the results
    • Question about testing this: use “formattedFOOurl” which takes the format
  • Without a respond_to, Rails delegates the type to a rendering engine based on the view filename extensions (More apple pie — and how we use HAML :D )
  • DT: could use “m.mysite.com” in routes.rb to render an iPhone formatted page by setting the foramt in routes.rb. (Slick idea)
  • .json support is in trunk but not 2.0.2 (waaah — that could help on my current project)
  • mimetypes.rb
    • #register and #registeralias
  • Chad is trying to get the class to talk more. DC people are so damned reserve. I was born on the wrong coast. God damn I need to move to the Portland or San Fran ASAP…..

ActiveResource

  • Damn it looks so simply. Now if only all apps used this instead of *cough*motherfuckingJRMP*cough*.
  • Just a quick walkthrough; too simple to warrant a thorough treatment.
  • Chad and Mike were talking about how wonderful it would be if all applications supported the Rails .xml protocol.
    • All that I could think (and sing quietly) was cue John Lennon “Imagine all the applications living in harmony….”
  • 201 code is the status returned when an object is crated (quick google to here verified out of curiousity)
  • Ah, to call a custom resource: Event.get(:search, :q => ‘ruby’)
    • http://localhost/events/search.xml?q=ruby
    • Again, not necessarily RESTful but how Rails does it and so how ActiveResource does it….
  • Authentication: ARclass.authenticate
  • Pain point brought up: Using ‘from_xml’ tightly couples the XML to the model

break

Note to self: play with ActiveResource client to my own “events” web app tonight

Testing (all afternoon — AWESOME)

When asked, when asked if their ‘opposite number’ in the class tests, half as many people said ‘yes’ as said that they tested. Maybe 20% of the class considers themselves rigorous testers of their software. I will assume that they are very humble or else I will be very sad. * DT: Unit testing is useful for finding design flaws / finding where there is too much coupling (for instance, where the setup is onerous) * DT is lecturing people on why they should test. * DT: only uses integration tests to exercise particularly tricky cases * MC: Testing is 90% about discipline (you betcha). * DT: Preaching to keep tests DRY by factoring commonalities into test helpers and splitting helpers into multiple files when they get too big (more motherhood and apple pie) * Improves test readability * Makes tests more flexable * assertequals ‘musician programmer’, users(:fred).tagnames sucks compared to assrthastags ‘musician programmer’, :fred * Latter could allow for different tag ordering * Test is more readable * They throw up a slide using a Rails Integration Test that defines several methods on an IntegratonTest#open_session session to create an integration test DSL. Awfully damn readable. * I could see using RSpec Stories that way. However, Dave Chem and the RSpec team seem to advocate a Stories-first approach. I don’t quite feel that; My gut (large as it is) tells me that I would spend far more time writing stories than I would need — where need means that I could get by with using specs instead of stories.

Mocking/Stubbing

  • DT: Describing mocks and stubs (motherhood and apple again……)
  • MC: Describing mocking in controllers (getting a bit bored now; can we get back to the theory?)
  • Maybe was worth it? FlexMock is a little niftier than I thought.
  • Ok, better, now we’re debating about what makes a test more readable.
    • I mentioned my habit of using hashes to simulate named_args. DT accused me of being a Smalltalk programmer. Said that I evolved from a Java programmer. ;)
  • CF: Describing RSpec Stories
    • Ok, cool, they’ve split most of the text of the story from the tests for each step. Pretty cool.
    • “Sentences” from Story are mapped to code blocks in registration steps in a separate file. Makes the story readable — although separating the Story into two files bugs me slightly.
    • Why not replace the pseudo-English version with a full-on rule-based English version using Treetop? Then the “Ringrish” can be replaced by English?
  • MC: Describing Shoulda — not as powerful as RSpec but, well, not as powerful as RSpec

Update: Sorry for some of the crappy formatting. I had TextMate convert Markdown to HTML and, evidentally, it mutilated a lot of what I typed….

Posted by evan on Monday, May 05, 2008

blog comments powered by Disqus