Add routes with a rails plugin or gem

written by paul on September 28th, 2007 @ 01:44 PM

It is possible to define routes in a ruby on rails plugin or gem. Normally, adding routes looks like this:


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

The problem is that the draw method clears the existing routes before adding the new ones (Ruby on Rails 1.2.3: routing.rb):


def draw
  clear!
  yield Mapper.new(self)
  named_routes.install
end

The plugins and gems are loaded first, so any new routes are cleared when config/routes.rb is loaded. One solution is to redefine the clear! method to do nothing:


class << ActionController::Routing::Routes;self;end.class_eval do
  define_method :clear!, lambda {}
end

The final result should be included in the plugin or gem:


class << ActionController::Routing::Routes;self;end.class_eval do
  define_method :clear!, lambda {}
end

ActionController::Routing::Routes.draw do |map|
  map.connect 'newurl', :controller => 'plugin_controller', :action => 'some_action'
end

Comments

  • Ola Bini on 28 Sep 14:24

    Doesn't it seem kind of excessive to change clear!? Wouldn't it be better to add a new method to Routes - something called add_routes, that does exactly the same thing as draw, except for not calling clear!.
  • Bernardo Heynemann on 28 Sep 15:10

    Hi Paul, As I explained in my blog post, I guess a cleaner option might be to just include your items and then yield a mapper, so other methods keep doing their mapping. Something like this: #used to allow proper Theming. def draw begin clear! mapper = Mapper.new(self) create_theme_routes(mapper) yield mapper named_routes.install rescue raise end end def create_theme_routes(map) map.named_route 'theme_images', "/themes/:theme/images/*filename", :controller=>'theme', :action=>'images' map.named_route 'theme_stylesheets', "/themes/:theme/stylesheets/*filename", :controller=>'theme', :action=>'stylesheets' map.named_route 'theme_javascript', "/themes/:theme/javascript/*filename", :controller=>'theme', :action=>'javascript' map.connect "/themes/*whatever", :controller=>'theme', :action=>'error' end That worked very well for me. Hope it helps! :) I didn´t try it out with multiple redefinitions by several plug-ins or gems though. I´m kinda newbie anyway! :)
  • Bernardo Heynemann on 28 Sep 15:12

    Sorry, it didn´t came out very well. I guess if you´d like to check the code you´d rather check my blog post at http://manicprogrammer.com/cs/blogs/heynemann/archive/2007/09/21/theme-support-in-rails-and-a-wild-community.aspx Cheers,
  • Paul Gross on 28 Sep 17:04

    My goal with this code is to write a plugin that just works out of the box with its own routes. There are definitely cleaner ways to monkey patch the routes, but then the user would have to change their routes.rb file. With my solution, a user does not have to do anything beyond installing the plugin.
  • James Adam on 01 Oct 08:21

    There has been discussion about this for a while on the engines-developers list. Most recently here: http://www.ruby-forum.com/topic/126316#563328 My feelings are that it's a mistake to *automatically* include routes from a plugin, because there's no way you can be sure where those routes should go in the order of precidence. If you put your automagic routes at the top, there's no way the user can override any of your plugin routes. If you add them at the bottom, then it's possible the applications own routes will be so generic that your plugin routes will never be reached... either way, it's not going to work well in general cases. The solution I proposed (and implemented) was that the user (read: developer) can easily include routes from a plugin at any point within their routes file, via a new method (map#from_plugin). I think this gives a good tradeoff between ease of use and flexibility in different applications. As I mention in the thread linked above, I don't think that "zero end user intervention" is the best goal to aim for when developing plugins that are "rich".

Post a comment

Options:

Size

Colors