1. Patch Rails3 route helpers to use STI base class.

    Monday 11th of October, 2010 at 10:20am Permalink.

    If you’ve perused the source of any moderately complicated Rails application you are likely to have come across the Single Table Inheritance (STI) pattern.  STI allows you to have polymorphic models all stored in the same table or collection. It may be best to give you an example:

    As you can see from the example, we have three models, Meat, Bacon and ChunkyBacon all using the “meats” table for storage.  This is really great, especially if there is common model logic (attributes, validations, life-cycle callbacks, etc) needed for all three models, and extra logic on the child models (imagine ChunkyBacon has a season).

    Kimono makes extensive use of STI behaviour throughout it’s model graph, although built upon the Mongoid ORM.  I kept running into problems where I needed to have routes for every new subclass I created and it didn’t really fit the way I wanted the application to work.  The problem is not actually the router (a simple map.resources :meats) works perfectly, but with the route helpers. A call to url_for or link_to when passed in a model instance would throw an exception because there were no routes defined for Bacon or ChunkyBacon.  I started with overriding the helpers (link_to, et al) but soon discovered this didn’t work well enough because the assumptions Rails makes about routing your models go deep.  How deep? To ActionDispatch::Routing::PolymorphicRoutes as it turns out.

    In order to create the behaviour I wanted I needed to add a reusable method to climb up a model’s superclass chain checking if the parent is a Mongoid document until it reaches the top of the inheritance tree,  then I needed to patch “build_named_route_call” to use this instead of just using the class of the model being routed.  Enter lib/kimono/routing.rb:

    Once that’s done, I simply add an initialiser to patch in the behaviour I want:

    Now when I call url_for(@bacon) I get “/meats/1” back.  Thanks Ruby.

  2. blog comments powered by Disqus

Archive