Skip to content

Instantly share code, notes, and snippets.

@dhh
Created April 25, 2012 18:44
Show Gist options
  • Save dhh/2492118 to your computer and use it in GitHub Desktop.
Save dhh/2492118 to your computer and use it in GitHub Desktop.
class ActionDispatch::Routing::Mapper
def draw(routes_name)
instance_eval(File.read(Rails.root.join("config/routes/#{routes_name}.rb")))
end
end
BCX::Application.routes.draw do
draw :api
draw :account
draw :session
draw :people_and_groups
draw :projects
draw :calendars
draw :legacy_slugs
draw :ensembles_and_buckets
draw :globals
draw :monitoring
draw :mail_attachments
draw :message_preview
draw :misc
root to: 'projects#index'
end
@jocubeit
Copy link

jocubeit commented May 9, 2012

Another slight update to @kulesa's solution for namespace support. This adds support for scope, in addition to namespace routes ( see https://gist.github.com/2507892 ):

class ActionDispatch::Routing::Mapper
  def draw(routes_name)
    instance_eval(File.read(Rails.root.join("config/routes#{@scope[:path]}", "#{routes_name}.rb")))
  end
end

@freegenie
Copy link

seems like routes get cached in development env, any advice on how to avoid it?

@shaynekang
Copy link

@knoopx
Copy link

knoopx commented Nov 8, 2012

@rtdp
Copy link

rtdp commented Jan 27, 2013

@freegenie +1
any workaround to that?

@apneadiving
Copy link

To get paths reloaded in dev mode, I ended up using in application.rb:

config.paths['config/routes'].unshift *Dir[Rails.root.join('config/routes/*.rb')]

Not the best line of code ever but does the job..

@volontarian
Copy link

@apneadiving Thanks! Additionally I had to wrap the code in config/routes/*.rb files by a "ApplicationName::Application.routes.draw do" block otherwise I get undefined method `resources'.

@logicalhan
Copy link

@apeadiving @applicat I think it might be better form to throw that line into config/environments/development.rb rather than application.rb, since it is unclear to me how this would affect the loading order of the routes. This way, at the very least, in production the @dhh 's 'draw' method would allow your routes to be defined in the order that you declare each draw method.

@volontarian
Copy link

@logical42 You could make a diff of "rake routes" results on your terminal before and after to see the affect on loading order.

But after some Rails updates my application is now on Rails 3.2.13 and don't need these hacks anymore (path unshifting and "ApplicationName::Application.routes.draw do" block).

Reload just seem to work through Rails now.

@evilmarty
Copy link

This is an awesome feature. Is it in master yet? I'm unable to find it in the code nor is it documented.

@rubytastic
Copy link

this fails for RAILS 4:

config.paths['config/routes'].unshift Dir[Rails.root.join('config/routes/.rb')]

Any thoughts?

@shime
Copy link

shime commented Sep 20, 2013

@rubytastic you can always force Rails to reload routes from your middleware!

class RoutesReloader
  def initialize(app)
    @app = app
  end

  def call(env)
    Rails.application.reload_routes!

    @app.call(env)
  end
end

# in config/environments/development.rb

config.middleware.use RoutesReloader

Enjoy reloading routes on every request!

@sharipov-ru
Copy link

@shime it works, but makes application very slow:

time = Benchmark.measure { 10.times { Rails.application.reload_routes!  }  }

=> #<Benchmark::Tms:0x007fb4809b3840
 @cstime=0.0,
 @cutime=0.0,
 @label="",
 @real=4.654909,
 @stime=0.020000000000000018,
 @total=4.640000000000004,
 @utime=4.6200000000000045>

It adds more than 450 ms for every request.

Hopefully there is still other possible solution: we can use ActiveSupport::FileUpdateChecker for tracking changes in config/routes directory:

class RoutesReloader
  ROUTES_PATH = Dir.glob("config/routes/*.rb")

  def initialize(app)
    @app = app

    @routes_reloader = ActiveSupport::FileUpdateChecker.new(ROUTES_PATH) do
      Rails.application.reload_routes!
    end
  end

  def call(env)
    @routes_reloader.execute_if_updated

    @app.call(env)
  end
end

@joxxoxo
Copy link

joxxoxo commented Sep 8, 2015

@sharipov-ru, it's much better but I'd like to add a small improvement:
ActiveSupport::FileUpdateChecker.new([], 'config/routes' => 'rb') do ... end
This way it should find new files as well.

@iGEL
Copy link

iGEL commented Nov 12, 2015

Guys, it's very outdated. You now can just require other routes files without monkey patching, they just have to repeat the Rails.application.routes.draw do:
config/routes.rb:

Rails.application.routes.draw do
  load Rails.root.join("config/routes/dev.rb")
  #...
end

config/routes/dev.rb:

Rails.application.routes.draw do
  scope "dev" do
    # ...
  end
end

No dynamic reloading tho, probably @sharipov-ru's reloader still works.

@h0jeZvgoxFepBQ2C
Copy link

h0jeZvgoxFepBQ2C commented Dec 7, 2016

Anyone found a nice solution on how to seperate route files and still make them auto reloading during development?

Edit: Going now with a combination of the mentioned solutions...

# config/environments/development.rb
class RoutesReloader
  def initialize(app)
    @app = app

    @routes_reloader = ActiveSupport::FileUpdateChecker.new([], 'config/routes' => 'rb') do
      Rails.application.reload_routes!
    end
  end

  def call(env)
    @routes_reloader.execute_if_updated

    @app.call(env)
  end
end

Rails.application.routes.draw do
  ...
  config.middleware.use RoutesReloader
end
# config/routes.rb
Rails.application.routes.draw do
  routes = [:admin_routes, :admin_routes_old, :public_routes, :api_routes]
  routes.each{ |route_file| load Rails.root.join("config", "routes", "#{route_file}.rb") }
end

@JosueMerlos
Copy link

How can I use concern with this conven?
https://guides.rubyonrails.org/routing.html#routing-concerns

concern :commentable do
  resources :comments
end
resources :messages, concerns: :commentable

can I do this?

draw :api, concerns: :commentable

or there another way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment