Lately I have been working on a Rails project with routes that have been getting more and more complicated. The project has three different user types. Each user has routes that are only visible when they’re signed in, plus public routes, with some that are only visible when certain users are signed in, and some of the routes are repeated under different namespaces, or with different constraints.

Since the routes file has been expanding over time, I decided that it would be best to split it up into smaller, easier to read and manage files. After doing a search on multiple rails route files to find out how to configure my application for this, I found this simple one line solution that you can add to your config/application.rb file in a Rails 3.2 or higher application:

1 config.paths["config/routes"] += Dir[Rails.root.join("config", "routes", "*.rb")]

What that does is tell your application to use any file located in config/routes as a routing file.

However, there were a couple of drawbacks I found in using this method. First, since config/application.rb is only loaded once when your application boots, if you were to add, rename, or delete any files in the config/routes directory, you would need to restart your application for the changes to become effective.

But the biggest issue, and the reason I chose not to use this method, is that it does not allow you to specify the order in which the routes are loaded. And for the application I’m working on the routes need to be loaded in a specific order.

So I ended up having to write my own method of using multiple route files, which is in the form of a very simple routing extension that looks like this:

 1 # File: config/initializers/routing_extensions.rb
 2 class ActionDispatch::Routing::Mapper
 3   def draw(*names)
 4     names.each do |name|
 5       file = Rails.root.join("config", "routes", "#{name.to_s}.rb")
 6       code = File.read(file)
 7       eval(code)
 8     end
 9   end
10 end

Now I can specify the exact order the external route files should be loaded in, when the routes should be loaded, and even use them more than once. For example, here is a very small portion of the routes in the application I am working on right now:

 1 # File: config/routes.rb
 2 AppName::Application.routes.draw do
 3   devise_for :admin, :user
 4 
 5   authenticated(:user) { draw :authenticated }
 6 
 7   authenticated(:admin) do
 8     namespace(:admin) { draw :authenticated }
 9   end
10 
11   draw :public
12 end
1 # File: config/routes/authenticated.rb
2 resource :dashboard, :only => [:show]
3 resource :preferences, :only => [:edit, :update]
4 root :to => "dashboards#show"
1 # File: config/routes/public.rb
2 get "/about" => "about#show"
3 root :to => "about#show"
comments powered by Disqus