Skip to content
This repository
Browse code

Merge pull request #8658 from senny/8649_unify_routes_output_for_cons…

…ole_and_web

Unify routes output for console and web, ensure engine routes are shown in html routes table.

Closes #8649.
  • Loading branch information...
commit a6cec6e8ed7cc158fa1bc3cc59a5c3fa392b2afe 2 parents 1e1c7af + 80795e0
Carlos Antonio da Silva authored January 05, 2013
4  actionpack/CHANGELOG.md
Source Rendered
@@ -560,7 +560,9 @@
560 560
 
561 561
     *Carlos Galdino + Rafael Mendonça França*
562 562
 
563  
-*   Show routes in exception page while debugging a `RoutingError` in development. *Richard Schneeman and Mattt Thompson*
  563
+*   Show routes in exception page while debugging a `RoutingError` in development.
  564
+
  565
+    *Richard Schneeman + Mattt Thompson + Yves Senn*
564 566
 
565 567
 *   Add `ActionController::Flash.add_flash_types` method to allow people to register their own flash types. e.g.:
566 568
 
27  actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -2,7 +2,6 @@
2 2
 require 'action_dispatch/middleware/exception_wrapper'
3 3
 require 'action_dispatch/routing/inspector'
4 4
 
5  
-
6 5
 module ActionDispatch
7 6
   # This middleware is responsible for logging exceptions and
8 7
   # showing a debugging page in case the request is local.
@@ -42,12 +41,11 @@ def render_exception(env, exception)
42 41
           :application_trace => wrapper.application_trace,
43 42
           :framework_trace => wrapper.framework_trace,
44 43
           :full_trace => wrapper.full_trace,
45  
-          :routes => formatted_routes(exception),
  44
+          :routes_inspector => routes_inspector(exception),
46 45
           :source_extract => wrapper.source_extract,
47 46
           :line_number => wrapper.line_number,
48 47
           :file => wrapper.file
49 48
         )
50  
-
51 49
         file = "rescues/#{wrapper.rescue_template}"
52 50
         body = template.render(:template => file, :layout => 'rescues/layout')
53 51
         render(wrapper.status_code, body)
@@ -85,11 +83,28 @@ def stderr_logger
85 83
       @stderr_logger ||= ActiveSupport::Logger.new($stderr)
86 84
     end
87 85
 
88  
-    def formatted_routes(exception)
  86
+    def routes_inspector(exception)
89 87
       return false unless @routes_app.respond_to?(:routes)
90 88
       if exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)
91  
-        inspector = ActionDispatch::Routing::RoutesInspector.new
92  
-        inspector.collect_routes(@routes_app.routes.routes)
  89
+        ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes)
  90
+      end
  91
+    end
  92
+
  93
+    class TableRoutesFormatter
  94
+      def initialize(view)
  95
+        @view = view
  96
+        @buffer = []
  97
+      end
  98
+
  99
+      def section(type, title, routes)
  100
+        @buffer << %(<tr><th colspan="4">#{title}</th></tr>)
  101
+        @buffer << @view.render(partial: "routes/route", collection: routes)
  102
+      end
  103
+
  104
+      def result
  105
+        @view.raw @view.render(layout: "routes/route_wrapper") {
  106
+          @view.raw @buffer.join("\n")
  107
+        }
93 108
       end
94 109
     end
95 110
   end
4  actionpack/lib/action_dispatch/middleware/templates/rescues/routing_error.erb
@@ -15,6 +15,7 @@
15 15
   <% end %>
16 16
   <%= render template: "rescues/_trace" %>
17 17
 
  18
+<% if @routes_inspector %>
18 19
   <h2>
19 20
     Routes
20 21
   </h2>
@@ -23,6 +24,5 @@
23 24
     Routes match in priority from top to bottom
24 25
   </p>
25 26
 
26  
-<%= render layout: "routes/route_wrapper" do %>
27  
-  <%= render partial: "routes/route", collection: @routes %>
  27
+  <%= @routes_inspector.format(ActionDispatch::DebugExceptions::TableRoutesFormatter.new(self)) %>
28 28
 <% end %>
62  actionpack/lib/action_dispatch/routing/inspector.rb
@@ -61,21 +61,33 @@ def engine?
61 61
 
62 62
     ##
63 63
     # This class is just used for displaying route information when someone
64  
-    # executes `rake routes`.  People should not use this class.
  64
+    # executes `rake routes` or looks at the RoutingError page.
  65
+    # People should not use this class.
65 66
     class RoutesInspector # :nodoc:
66  
-      def initialize
67  
-        @engines = Hash.new
  67
+      def initialize(routes)
  68
+        @engines = {}
  69
+        @routes = routes
68 70
       end
69 71
 
70  
-      def format(all_routes, filter = nil)
71  
-        if filter
72  
-          all_routes = all_routes.select{ |route| route.defaults[:controller] == filter }
  72
+      def format(formatter, filter = nil)
  73
+        routes_to_display = filter_routes(filter)
  74
+
  75
+        routes = collect_routes(routes_to_display)
  76
+        formatter.section :application, 'Application routes', routes
  77
+
  78
+        @engines.each do |name, routes|
  79
+          formatter.section :engine, "Routes for #{name}", routes
73 80
         end
74 81
 
75  
-        routes = collect_routes(all_routes)
  82
+        formatter.result
  83
+      end
76 84
 
77  
-        formatted_routes(routes) +
78  
-          formatted_routes_for_engines
  85
+      def filter_routes(filter)
  86
+        if filter
  87
+          @routes.select { |route| route.defaults[:controller] == filter }
  88
+        else
  89
+          @routes
  90
+        end
79 91
       end
80 92
 
81 93
       def collect_routes(routes)
@@ -100,22 +112,32 @@ def collect_engine_routes(route)
100 112
           @engines[name] = collect_routes(routes.routes)
101 113
         end
102 114
       end
  115
+    end
103 116
 
104  
-      def formatted_routes_for_engines
105  
-        @engines.map do |name, routes|
106  
-          ["\nRoutes for #{name}:"] + formatted_routes(routes)
107  
-        end.flatten
  117
+    class ConsoleFormatter
  118
+      def initialize
  119
+        @buffer = []
108 120
       end
109 121
 
110  
-      def formatted_routes(routes)
111  
-        name_width = routes.map{ |r| r[:name].length }.max
112  
-        verb_width = routes.map{ |r| r[:verb].length }.max
113  
-        path_width = routes.map{ |r| r[:path].length }.max
  122
+      def result
  123
+        @buffer.join("\n")
  124
+      end
114 125
 
115  
-        routes.map do |r|
116  
-          "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
117  
-        end
  126
+      def section(type, title, routes)
  127
+        @buffer << "\n#{title}:" unless type == :application
  128
+        @buffer << draw_section(routes)
118 129
       end
  130
+
  131
+      private
  132
+        def draw_section(routes)
  133
+          name_width = routes.map { |r| r[:name].length }.max
  134
+          verb_width = routes.map { |r| r[:verb].length }.max
  135
+          path_width = routes.map { |r| r[:path].length }.max
  136
+
  137
+          routes.map do |r|
  138
+            "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
  139
+          end
  140
+        end
119 141
     end
120 142
   end
121 143
 end
22  actionpack/test/dispatch/debug_exceptions_test.rb
@@ -45,8 +45,17 @@ def call(env)
45 45
     end
46 46
   end
47 47
 
48  
-  ProductionApp  = ActionDispatch::DebugExceptions.new(Boomer.new(false))
49  
-  DevelopmentApp = ActionDispatch::DebugExceptions.new(Boomer.new(true))
  48
+  def setup
  49
+    app = ActiveSupport::OrderedOptions.new
  50
+    app.config = ActiveSupport::OrderedOptions.new
  51
+    app.config.assets = ActiveSupport::OrderedOptions.new
  52
+    app.config.assets.prefix = '/sprockets'
  53
+    Rails.stubs(:application).returns(app)
  54
+  end
  55
+
  56
+  RoutesApp = Struct.new(:routes).new(SharedTestRoutes)
  57
+  ProductionApp  = ActionDispatch::DebugExceptions.new(Boomer.new(false), RoutesApp)
  58
+  DevelopmentApp = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp)
50 59
 
51 60
   test 'skip diagnosis if not showing detailed exceptions' do
52 61
     @app = ProductionApp
@@ -78,6 +87,15 @@ def call(env)
78 87
     assert boomer.closed, "Expected to close the response body"
79 88
   end
80 89
 
  90
+  test 'displays routes in a table when a RoutingError occurs' do
  91
+    @app = DevelopmentApp
  92
+    get "/pass", {}, {'action_dispatch.show_exceptions' => true}
  93
+    routing_table = body[/route_table.*<.table>/m]
  94
+    assert_match '/:controller(/:action)(.:format)', routing_table
  95
+    assert_match ':controller#:action', routing_table
  96
+    assert_no_match '&lt;|&gt;', routing_table, "there should not be escaped html in the output"
  97
+  end
  98
+
81 99
   test "rescue with diagnostics message" do
82 100
     @app = DevelopmentApp
83 101
 
25  actionpack/test/dispatch/routing/inspector_test.rb
@@ -8,7 +8,6 @@ module Routing
8 8
     class RoutesInspectorTest < ActiveSupport::TestCase
9 9
       def setup
10 10
         @set = ActionDispatch::Routing::RouteSet.new
11  
-        @inspector = ActionDispatch::Routing::RoutesInspector.new
12 11
         app = ActiveSupport::OrderedOptions.new
13 12
         app.config = ActiveSupport::OrderedOptions.new
14 13
         app.config.assets = ActiveSupport::OrderedOptions.new
@@ -17,9 +16,10 @@ def setup
17 16
         Rails.stubs(:env).returns("development")
18 17
       end
19 18
 
20  
-      def draw(&block)
  19
+      def draw(options = {}, &block)
21 20
         @set.draw(&block)
22  
-        @inspector.format(@set.routes)
  21
+        inspector = ActionDispatch::Routing::RoutesInspector.new(@set.routes)
  22
+        inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, options[:filter]).split("\n")
23 23
       end
24 24
 
25 25
       def test_displaying_routes_for_engines
@@ -40,7 +40,8 @@ def self.inspect
40 40
         expected = [
41 41
           "custom_assets GET /custom/assets(.:format) custom_assets#show",
42 42
           "         blog     /blog                    Blog::Engine",
43  
-          "\nRoutes for Blog::Engine:",
  43
+          "",
  44
+          "Routes for Blog::Engine:",
44 45
           "cart GET /cart(.:format) cart#show"
45 46
         ]
46 47
         assert_equal expected, output
@@ -165,6 +166,22 @@ def test_redirect
165 166
         assert_equal "   bar GET /bar(.:format)    redirect(307, path: /foo/bar)", output[1]
166 167
         assert_equal "foobar GET /foobar(.:format) redirect(301)", output[2]
167 168
       end
  169
+
  170
+      def test_routes_can_be_filtered
  171
+        output = draw(filter: 'posts') do
  172
+          resources :articles
  173
+          resources :posts
  174
+        end
  175
+
  176
+        assert_equal ["    posts GET    /posts(.:format)          posts#index",
  177
+                      "          POST   /posts(.:format)          posts#create",
  178
+                      " new_post GET    /posts/new(.:format)      posts#new",
  179
+                      "edit_post GET    /posts/:id/edit(.:format) posts#edit",
  180
+                      "     post GET    /posts/:id(.:format)      posts#show",
  181
+                      "          PATCH  /posts/:id(.:format)      posts#update",
  182
+                      "          PUT    /posts/:id(.:format)      posts#update",
  183
+                      "          DELETE /posts/:id(.:format)      posts#destroy"], output
  184
+      end
168 185
     end
169 186
   end
170 187
 end
4  railties/lib/rails/tasks/routes.rake
@@ -2,6 +2,6 @@ desc 'Print out all defined routes in match order, with names. Target specific c
2 2
 task routes: :environment do
3 3
   all_routes = Rails.application.routes.routes
4 4
   require 'action_dispatch/routing/inspector'
5  
-  inspector = ActionDispatch::Routing::RoutesInspector.new
6  
-  puts inspector.format(all_routes, ENV['CONTROLLER']).join "\n"
  5
+  inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
  6
+  puts inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, ENV['CONTROLLER'])
7 7
 end

0 notes on commit a6cec6e

Please sign in to comment.
Something went wrong with that request. Please try again.