Supercharging Routes.rb

Ben Scofield, Former Viget

Article Category: #Code

Posted on

I’ve crusaded against the catch-all route in Rails applications for a while now:

ActionController::Routing::Routes.draw do |map| # ... map.connect ':controller/:action/:id' end 

At the same time, I’ve been guilty of using something just as bad:

ActionController::Routing::Routes.draw do |map| # ... map.sandstone '*path', :controller => 'pages', :action => 'show' end 

That sandstone route is just one example of catching all requests (that aren’t handled by prior routes) and shoving them through a single controller action. You often see this in custom CMSs (like Sandstone), where you want to render templates on the filesystem or from a database, without having to manually declare each of them as a distinct route.

Well, no more! Let all catch-all routes die a horrible death! Instead, we can use Ruby to automatically add specific routes for each of our CMS-driven pages. Say your CMS stores templates to the database:

 

? ActionController::Routing::Routes.draw do |map| # ... map.with_options :controller => 'pages', :action => 'show' do |pages| Page.all.each do |page| eval "pages.#{page.short_name} '#{page.path}', :path => '#{page.path}'" end end end

 

Similarly, you could cycle over the templates in a specified, CMS-managed view directory to create custom routes for each defined page.

With this technique, we can escape the tyranny of the catch-all route once and for all! Join me, and live free!

Note: this technique does require some tweaking if your CMS allows you to create pages on the fly, since the routes are only loaded when the application is restarted. One workaround would be to manually add routes for new pages to the routemap when they are created - but that is left as an exercise for the reader.

Related Articles