Skip to content

Show Routes while Debugging RoutingError #6696

Merged
merged 3 commits into from Jul 8, 2012
@schneems
Ruby on Rails member

If someone receives a routing error, they likely need to view the routes. Rather than making them visit '/rails/info/routes' or run rake routes we can give them that information on the page.

Screenshot:
Screeshot

ActionDispatch Tests Pass

@schneems
Ruby on Rails member

The only real question was where to put the code to format the routes. In a more traditional architecture it would belong in the controller 100%. However, in other exceptions there are code blocks in the views , and while it doesn't make for clean view code, it does keep the middleware lean.

@rafaelfranca
Ruby on Rails member

Very cool. I would leave the formatter code in the middleware.

@rafaelfranca rafaelfranca commented on an outdated diff Jun 11, 2012
...ck/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -1,5 +1,7 @@
require 'action_dispatch/http/request'
require 'action_dispatch/middleware/exception_wrapper'
+require 'rails/application/route_inspector'
@rafaelfranca
Ruby on Rails member
rafaelfranca added a note Jun 11, 2012

I just realized that this will only work if railties is loaded in your application. As railties is not a actionpack dependency this can fail with a LoadError

@rafaelfranca
Ruby on Rails member
rafaelfranca added a note Jun 11, 2012

@josevalim thoughts about this?

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

👍 love the idea.

@josevalim
Ruby on Rails member

As @rafaelfranca, this is backwards, actionpack cannot depend on railties. In fact, every time you see a reference to the Rails constant in actionpack, it is something that needs to be fixed by providing a proper configuration or abstract (except in railties files).

That said, it seems the best way would be to move the router inspector to actionpack.

@tenderlove
Ruby on Rails member

Agree with @josevalim, we need to move the inspector to AP. I do like this idea, but we should be careful about performance of the 500 pages.

@josevalim
Ruby on Rails member
@schneems
Ruby on Rails member

ActionDispatch already knows quite a bit about routes, formatting them to be human readable doesn't seem like too far of a leap.

On the perf side it looks like DebugExceptions is in the middleware in production, but the custom error pages are ignored unless env['action_dispatch.show_detailed_exceptions'] is set. Restrict any route formatting/rendering code to within that section and there won't be any performance degradation.

@schneems
Ruby on Rails member
schneems commented Jul 5, 2012

@josevalim, @rafaelfranca, & @tenderlove I paired with @mattt to move the Route Inspector out of Railties, and into Actionpack (action_dispatch). Re-ran all railties tests (https://gist.github.com/b298e74a2d20863c9486) and AR with sqlite3 (https://gist.github.com/b298e74a2d20863c9486). ATP.

Now action_dispatch can render routes when routing errors are received independently of railties.

@josevalim
Ruby on Rails member

Thanks @schneems ! One thing left: could we move the route inspector tests to inside action dispatch too? Thanks!

@schneems schneems and 1 other commented on an outdated diff Jul 6, 2012
...ck/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -78,5 +81,13 @@ def logger(env)
def stderr_logger
@stderr_logger ||= ActiveSupport::Logger.new($stderr)
end
+
+ private
+ def formatted_routes(exception)
+ if exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)
+ inspector = ActionDispatch::Routing::RouteInspector.new
+ inspector.format(Rails.application.routes.routes).join("\n")
@schneems
Ruby on Rails member
schneems added a note Jul 6, 2012

We missed this reference Rails.application.routes.routes. Moving the inspector was the easy part, getting rid of that line will require more code changes. Right now railties builds routes using ActionDispatch, but ActionDispatch doesn't actually know what routes it has. This is the method in railties for Rails.application.routes.

def routes
  @routes ||= ActionDispatch::Routing::RouteSet.new.tap do |routes|
    routes.draw_paths.concat paths["config/routes"].paths
  end

  @routes.append(&Proc.new) if block_given?
  @routes
end

My first reaction is to keep ActionDispatch agnostic about where the routes come from, but to store the results, so that Railties can inject the path where it wants the routes to be drawn from. ActionDispatch, rather than just spitting out routes can hold onto them.

def routes
  @routes ||= ActionDispatch::Routing.set_from_paths(paths["config/routes"].paths)

  @routes.append(&Proc.new) if block_given?
  @routes
end

Then we could have a getter in ActionDispatch along the lines of ActionDispatch::Routing.routes, how does that sound?

(on a side note we should also make Journey an injectable dependency rather than hard coding it into ActionDispatch, though this isn't the place or time for that)

@josevalim
Ruby on Rails member
josevalim added a note Jul 6, 2012

You can simply pass the route set or Rails.application as argument to the middleware initialization.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@schneems
Ruby on Rails member
schneems commented Jul 6, 2012

Updated the middleware to take an optional routes_app that should respond to :routes. Also moved the route inspector test to action_dispatch, which you'll be happy to know shaves off 2 seconds from the railties test suite!!

ATP on ActionPack https://gist.github.com/56da1c69f269900bb51c, ActiveRecord, and Railties

@exviva exviva and 1 other commented on an outdated diff Jul 6, 2012
railties/lib/rails/application.rb
@@ -266,7 +266,7 @@ def default_middleware_stack
middleware.use ::ActionDispatch::RequestId
middleware.use ::Rails::Rack::Logger, config.log_tags # must come after Rack::MethodOverride to properly log overridden methods
middleware.use ::ActionDispatch::ShowExceptions, config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path)
- middleware.use ::ActionDispatch::DebugExceptions
+ middleware.use ::ActionDispatch::DebugExceptions, Rails.application
@exviva
exviva added a note Jul 6, 2012

Couldn't this simply be self instead of Rails.application?

@schneems
Ruby on Rails member
schneems added a note Jul 6, 2012

yes, and there is a line a little lower that sets app = self, it might be more clear to move that line up and use the app var rather than relying on the hard coded

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@schneems
Ruby on Rails member
schneems commented Jul 6, 2012

updated

@josevalim
Ruby on Rails member

This looks good to be merged in my opinion. It needs to be rebased though and we need a changelog entry. :) Thanks!

schneems and others added some commits Jun 9, 2012
@schneems schneems show routes while debugging RoutingError
If someone receives a routing error, they likely need to view the routes. Rather than making them visit '/rails/info/routes' or run `rake routes` we can give them that information on the page.
fa714ec
@mattt mattt move route_inspector to actionpack
this is so we can show route output in the development when we get a routing error. Railties can use features of ActionDispatch, but ActionDispatch should not depend on Railties.
ef91cdd
@schneems
Ruby on Rails member
schneems commented Jul 7, 2012

Rebased against upstream master, added changelog entry, let me know if there is anything else. Thanks for your help!

@josevalim josevalim merged commit 7404cda into rails:master Jul 8, 2012
@mike-burns

Fantastic!

@klevo
klevo commented Sep 20, 2012

So cool.

@rodrigoalvesvieira

Great idea!

@daniloassis

Simple but GREAT!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.