Dynamic Routes in Ruby On Rails

Whoah! Hold up there a second! This post is over 3 years old, so I've revised it.

Check it out at Dynamic Routes in Rails Redux.

I loathe the way that many HTML "templating" libraries try to turn HTML authoring into a series of method calls. I dislike CGI.pm's suite of start_html/end_html functions, for example (I'll be posting my detailed reasons why later). I also dislike the link_to helper in Ruby on Rails, and so don't often use it. I have been pleasantly surprised, however, by a hack that I've recently put in place on the new BusinessMentor.com.au site.

The secret here is the config/routes.rb configuration file. Although the concept of dynamic pages isn't new (the samples show examples on how to do something similar using id's), this technique works in the opposite direction.

In our case, we have a variety of categories of documents - about 20 or so. Being a perfectionist, I really don't like having URLs saying /category/list/1 10 points for noticing the not-so-correct naming. I'd much rather it had some meaning (and looked nicer) like /documents-and-services/policies - after all, that's what the category really is.

The problem we had was that I was going through, by hand, and adding in routes to say that /category/list/1 maps to policies, 2 to bat, etc. When you have almost 25 categories, that becomes a bit tedious. Furthermore, you have to change every link on other pages to look like the nice new style. When the stakeholders want to keep changing the categories, this becomes even more of an issue. Nay, a maintenance nightmare.

So what did we do? Simple - we request the list of categories from within routes.rb, iterate over the array, and populate the routes map automagically. Those that I haven't specified textual names for in the database just don't get a route added. Those that do get a nice mapping from /category/list/ID to /documents-and-services/CATEGORY.

So where does link_to come into all this? link_to will automagically find and use the best route to any link it is adding. So, when I make a link like link_to("Linky", :controller => "category", :action => "list", :id => 1), instead of making a usual, ugly looking link, Rails will make the link to /documents-and-services/policies instead. Congratulations folks, we now have nice looking URLs all through our site whenever we reference that page.

The beauty of all this is that Rails does the work, not me. You don't need to keep your routes.rb up to date with changes in the database - it happens at run time (and, from what I can tell, only when the dependencies are updated - as such, it should keep the route information until it absolutely must discard it). I have yet to do in depth performance testing, but so far in testing I have not noticed any major issues. I would actually expect for this method to be slightly more efficient than the method of using an :id in the routes, as the lookup runs once, rather than when the request is processed.

Dynamic Routes - Keeping your URLs clean...

(Posted 18July2005 because I forgot to actually post this...)