This project is archived and is in readonly mode.

#329 ✓duplicate
Rich Cavanaugh

Add an API for plugins to register routes

Reported by Rich Cavanaugh | June 4th, 2008 @ 02:26 AM | in 2.x

This change allows plugins to register routes while maintaining control for the developer using the plugin.

This is how a plugin registers it's routes:

config.draw_for do |map|
  map.connect ...
  map.resources ...

# or

config.draw_for :my_plugin_admin do |map|
  map.connect ...
  map.resources ...

This is how a developer would install the plugin routes:

ActionController::Routing::Routes.draw do |map|
  # Install every registered plugin route.
  # Same as above.
  map.plugin_routes :all
  # Install the listed plugin routes.
  map.plugin_routes :hobo, :active_scaffold, :restful_authentication
  # The above approach could also be used multiple times
  # to handle order sensitive routes.
  map.plugin_routes :hobo
  map.connect '/something', ...
  map.plugin_routes :active_scaffold, :restful_authentication
  # Install every registered plugin route execept the listed plugins.
  map.plugin_routes :except => [:hobo, :something]

There are currently no tests for these changes. I will add tests soon. This patch includes the suggestions from DHH and technoweenie on #rails-contrib

Comments and changes to this ticket

  • Rich Cavanaugh

    Rich Cavanaugh June 4th, 2008 @ 02:27 AM

    Attaching the patch would probably help it make it into Rails.

  • Rick

    Rick June 4th, 2008 @ 02:29 AM

    • State changed from “new” to “open”
    • Assigned user set to “Rick”
  • Rick

    Rick June 4th, 2008 @ 03:36 AM

    Just a nitpick, but config.draw_for with no arguments looks weird. That's why I suggested config.plugin_routes or something to that effect in #rails-contrib. It's something that looks fine with or without a given plugin name.

  • Rich Cavanaugh
  • Rich Cavanaugh

    Rich Cavanaugh June 4th, 2008 @ 07:27 PM

    You're absolutely right, I should have caught that. I've changed the method name to plugin_routes but, I also setup an alias for draw_for so you could still do:

    config.draw_for :plugin_admin do |map|

    The unadorned approach is now:

    config.plugin_routes do |map|
  • Rich Cavanaugh

    Rich Cavanaugh August 12th, 2008 @ 09:06 AM

    • Tag set to actionpack, edge, enhancement, patch, railties, routing

    I've attached the finalized patch updated for edge and added tests.

  • voxdolo

    voxdolo August 13th, 2008 @ 01:57 AM

    This looks like a great enhancement. I've wanted this functionality as a plugin developer several times. +1 here.

  • Bruno Miranda

    Bruno Miranda August 14th, 2008 @ 08:26 PM

    This would be awesome to have. +1

  • RSL

    RSL August 15th, 2008 @ 10:34 PM

    Question: is it really a good idea for routing information to be spread all over the rails app? and potentially conflicted between plugins? I'm much more comfortable with rake tasks and generators adding code to the routes.rb where you can easily see what's what. I'm all for this if someone could assuage those fears.

  • Rich Cavanaugh

    Rich Cavanaugh August 15th, 2008 @ 11:09 PM

    This change simply allows plugins to define their routes but does not automatically inject them into the actual routing.

    They are then inserted by the developers into config/routes.rb using code like:

      map.plugin_routes :hobo
      # or more automated
      map.plugin_routes :all

    So control remains entirely in the rails app developer's hands. They can control the precise order that all of the plugin routes are injected to avoid conflicts.

    At that point it's just a matter of the developer knowing what the plugins they're using are doing. If they don't, conflicts could happen in many places between plugins, not just routes.

  • azimux

    azimux August 16th, 2008 @ 10:26 AM

    I don't know if anybody has looked at the engines plugin, but it uses the syntax:

    map.from_plugin :some_plugin

    Then the plugin has a routes.rb in it's root directory and the routes in this file are evaled by the above call

  • RSL

    RSL August 16th, 2008 @ 05:17 PM

    rich, i misread developer to mean the plugin developer [my fault for reading too quickly]. great patch. +1

  • Ramon Salvadó
  • Michael Koziarski

    Michael Koziarski September 13th, 2008 @ 12:23 PM

    • Milestone set to 2.x

    I like this, or something like it, for the 2.3 stream.

    But for now I'm just moving it off the radar for 2.2

  • James Adam

    James Adam September 14th, 2008 @ 11:31 PM

    The engines plugin does indeed implement this, but in a much simpler, low-tech way. If this is going into core, it probably needs to work nicely with things like namespaces.

    Additionally, is there any way to avoid the 'currently_loading_plugin' attribute? It's a bit inelegant.

  • DHH

    DHH November 26th, 2008 @ 07:38 PM

    • State changed from “open” to “duplicate”

    I've added auto-loading of config/routes.rb from all plugins now.

  • James Adam

    James Adam May 1st, 2009 @ 06:23 PM

    • Tag changed from actionpack, edge, enhancement, patch, railties, routing to actionpack, edge, engines, enhancement, patch, plugin, railties, routing

    I think this functionality has real-world use, and would love to see it implemented. I've come up with a simple but clear example of a routing issue which is realistic and problematic given the current simplistic plugin route loading, in this gist

    I spiked locally and came up with a very similar patch, with a bit more flexibility and a few caveats; essentially a plugin (or any loading file) can register one or more 'bundles' of routes, and then the developer can load them at the point they choose.

    In a plugin

    ActionController::Routing::Routes.bundle(:my_plugin) do |map|
      map.connect "/login", :controller => "session", :action => "new"
      map.resource :session
      map.resources :users

    and in the app

    ActionController::Routing::Routes.draw do |map|
       map.bundle :my_plugin

    I'm not a huge fan of the currently_loading_plugin stuff, and prefer the explicit naming, but that's a minor quibble.

    There are two hiccups, as far as I can see. The first is that there's no clean way to generate a set of routes without having them append to the RouteSet; this means that when a bundle is mapped, it actually appends the routes to the end of the app routes, and then we have to slice them off and insert them where the bundle placeholder is.

    Secondly, again because of the current architecture of the Mapper/RouteSet, there's no way to pass options into a Mapper. This means that you can do, for example:

      map.with_options(:name_prefix => "admin_") do |map|
        map.bundle :my_plugin

    because there's no way to pass the options into the Mapper instance.

    However, even with these shortcomings, it feels like useful functionality for developers wanting to share routes in a flexible way.

  • James Adam

    James Adam May 1st, 2009 @ 06:30 PM

    See also #1450 - this kind of mechanism could cover the desired "manual when I want it, automatic when I don't care" functionality.

  • James Adam

    James Adam May 1st, 2009 @ 06:54 PM

    Here's my patch, with tests. Works pretty well, I think. The only thing I haven't changed is the doc at the top.

    This patch incorporates functionality from ticket #349 which describes wanting to manually load routes when specified, and automatically when not.

  • James Adam

    James Adam May 1st, 2009 @ 06:55 PM

    Oops, make that ticket #1450

  • jesse (at jesseclark)

    jesse (at jesseclark) May 18th, 2009 @ 06:58 PM

    I like the idea of giving the app developer control over how the plugin routes get integrated instead of automatically having plugin routes override application routes.

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href=""></a>

Referenced by