#80 Routing Partials


The routes file can grow to be unmaintainable and messy. Learn to keep things organized by extracting out blocks of routes into their own files.
rails routes 4:30


Gitlab Source - https://gitlab.com/gitlab-org/gitlab-ce
Episode Source - https://github.com/driftingruby/080-routing-partials

Side Note: everyone should use caution in using instance_eval and be careful to not accept user inputs (or ensure they are sanitized). I feel that it is an acceptable use case here since only the code in the routes will call this method and it is not exposed.


config/initializers/routing_draw.rbclass ActionDispatch::Routing::Mapper
  def draw(routes_name, sub_path=nil)
    if sub_path.present?
routes.rbRails.application.routes.draw do
  draw :api
  resources :users
  root to: 'users#index'
config/routes/api.rbrequire 'api_constraints'

namespace :api, compress: false do
  [:v1, :v2].map { |api| draw api, :api }
config/routes/api/v1.rbscope module: :v1, constraints: ApiConstraints.new(version: 1, default: false) do
  resources :users

davearonson said over 2 years ago on Routing Partials :

Just wondering about the use of .map there.  Does the mapper actually somehow use the result of each call, so that it becomes important to use .map, or is the important part more of a side-effect, so that .each would do?  If the latter, I think that would be clearer as it wouldn't raise this question, in the minds of those of us who tend to overthink things.  :-)

kobaltz PRO said over 2 years ago on Routing Partials :

Either should work since the method is calling instance_eval.

Sam Van Damme PRO said over 2 years ago on Routing Partials :

Does this slow down your app? Are those partials loaded at every request?

kobaltz PRO said over 2 years ago on Routing Partials :

Honestly, I've not done any benchmarking.

However, I would assume that if it is loading the route partials, it would add some kind of overhead. That being said, I would also argue that the overhead would be minimal.  Given the number of controllers that gitlab uses and its performance that i've experienced, any kind of overhead would be worth the added maintainability.

Also, I think that this would just be a valid point on a development environment. By default, if you were to change routes in production, you would have to restart the application to pick up the changes.

Sam Van Damme PRO said over 2 years ago on Routing Partials :

Got it, thanks for your comment! Implementing it now :)

dan.legrand said over 2 years ago on Routing Partials :

I have a massive routes file on an app I'm working on right now, and it has several namespaced sections, so this episode was just at the right time!

One thought, though.

Instead of: draw :filename, "sub_path", why not use: draw "sub_path/filename" ?

Putting the sub_path as a param after the name seems slightly confusing to me.  When I want to know "where" the file is, it's easier to see "sub_path/filename".  Just a thought!  I found this episode very helpful.

kobaltz PRO said over 2 years ago on Routing Partials :

In hindsight, you're right. Either way should work with the latter being more clear.

dancinglightning said over 2 years ago on Routing Partials :

Nice idea of splitting large route files. 

But am i misunderstanding something or could you just as well use require_relative , either directly or instead of the instance_eval ?

kobaltz PRO said over 2 years ago on Routing Partials :

The code will start to get messy. You wouldn't be able to simply extract out the routes into another file. You would have to still use the Rails.application.routes.draw, but then would also need to figure out how to not overwrite what you've already required. The method that I've demonstrated in this episode was fairly unobtrusive.

You could however, do something like this

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

And it would probably have a similar effect, however, I don't think that it is as 'clean'.

Arkadiusz Oleksy said over 2 years ago on Routing Partials :


You can simplify your draw method to not branch out on subpath. Pathname#join accepts multiple arguments and if one of them is empty string, then it will not be included in created path:

def draw(routes_name, sub_path=nil)
  Rails.root.join('config/routes', sub_path.to_s, "#{routes_name}.rb")
draw :v1, 'api'
# => #<Pathname:/path/to/app/config/routes/api/v1.rb>
draw :v1
# => #<Pathname:/path/to/app/config/routes/v1.rb>

Login to Comment