actionpack 4.2.11.1 → 5.2.4.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (166) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +287 -488
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/lib/abstract_controller/asset_paths.rb +2 -0
  6. data/lib/abstract_controller/base.rb +45 -49
  7. data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +47 -31
  10. data/lib/abstract_controller/collector.rb +8 -11
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +25 -25
  13. data/lib/abstract_controller/logger.rb +2 -0
  14. data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
  15. data/lib/abstract_controller/rendering.rb +42 -41
  16. data/lib/abstract_controller/translation.rb +10 -7
  17. data/lib/abstract_controller/url_for.rb +2 -0
  18. data/lib/abstract_controller.rb +12 -5
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +27 -19
  22. data/lib/action_controller/caching.rb +14 -57
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +10 -15
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +118 -44
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +27 -46
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
  32. data/lib/action_controller/metal/exceptions.rb +8 -14
  33. data/lib/action_controller/metal/flash.rb +4 -3
  34. data/lib/action_controller/metal/force_ssl.rb +23 -21
  35. data/lib/action_controller/metal/head.rb +21 -19
  36. data/lib/action_controller/metal/helpers.rb +24 -14
  37. data/lib/action_controller/metal/http_authentication.rb +64 -57
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +19 -21
  40. data/lib/action_controller/metal/live.rb +90 -106
  41. data/lib/action_controller/metal/mime_responds.rb +33 -46
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +61 -53
  44. data/lib/action_controller/metal/redirecting.rb +49 -28
  45. data/lib/action_controller/metal/renderers.rb +87 -44
  46. data/lib/action_controller/metal/rendering.rb +72 -50
  47. data/lib/action_controller/metal/request_forgery_protection.rb +229 -93
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +12 -10
  50. data/lib/action_controller/metal/strong_parameters.rb +583 -164
  51. data/lib/action_controller/metal/testing.rb +2 -17
  52. data/lib/action_controller/metal/url_for.rb +19 -10
  53. data/lib/action_controller/metal.rb +98 -83
  54. data/lib/action_controller/railtie.rb +28 -10
  55. data/lib/action_controller/railties/helpers.rb +2 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +280 -411
  59. data/lib/action_controller.rb +29 -21
  60. data/lib/action_dispatch/http/cache.rb +93 -47
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +26 -20
  63. data/lib/action_dispatch/http/filter_redirect.rb +10 -11
  64. data/lib/action_dispatch/http/headers.rb +55 -22
  65. data/lib/action_dispatch/http/mime_negotiation.rb +56 -41
  66. data/lib/action_dispatch/http/mime_type.rb +134 -121
  67. data/lib/action_dispatch/http/mime_types.rb +20 -6
  68. data/lib/action_dispatch/http/parameter_filter.rb +25 -11
  69. data/lib/action_dispatch/http/parameters.rb +98 -39
  70. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  71. data/lib/action_dispatch/http/request.rb +200 -118
  72. data/lib/action_dispatch/http/response.rb +225 -110
  73. data/lib/action_dispatch/http/upload.rb +12 -6
  74. data/lib/action_dispatch/http/url.rb +110 -28
  75. data/lib/action_dispatch/journey/formatter.rb +55 -32
  76. data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
  79. data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
  80. data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
  83. data/lib/action_dispatch/journey/nodes/node.rb +18 -6
  84. data/lib/action_dispatch/journey/parser.rb +23 -22
  85. data/lib/action_dispatch/journey/parser.y +3 -2
  86. data/lib/action_dispatch/journey/parser_extras.rb +12 -4
  87. data/lib/action_dispatch/journey/path/pattern.rb +50 -44
  88. data/lib/action_dispatch/journey/route.rb +106 -28
  89. data/lib/action_dispatch/journey/router/utils.rb +20 -11
  90. data/lib/action_dispatch/journey/router.rb +35 -23
  91. data/lib/action_dispatch/journey/routes.rb +18 -16
  92. data/lib/action_dispatch/journey/scanner.rb +18 -15
  93. data/lib/action_dispatch/journey/visitors.rb +99 -52
  94. data/lib/action_dispatch/journey.rb +7 -5
  95. data/lib/action_dispatch/middleware/callbacks.rb +1 -2
  96. data/lib/action_dispatch/middleware/cookies.rb +304 -193
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
  98. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  99. data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
  100. data/lib/action_dispatch/middleware/executor.rb +21 -0
  101. data/lib/action_dispatch/middleware/flash.rb +78 -54
  102. data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
  103. data/lib/action_dispatch/middleware/reloader.rb +5 -91
  104. data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
  105. data/lib/action_dispatch/middleware/request_id.rb +17 -9
  106. data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
  107. data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
  108. data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
  109. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
  110. data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
  111. data/lib/action_dispatch/middleware/ssl.rb +114 -36
  112. data/lib/action_dispatch/middleware/stack.rb +31 -44
  113. data/lib/action_dispatch/middleware/static.rb +57 -50
  114. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
  115. data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
  121. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
  124. data/lib/action_dispatch/railtie.rb +19 -11
  125. data/lib/action_dispatch/request/session.rb +106 -59
  126. data/lib/action_dispatch/request/utils.rb +67 -24
  127. data/lib/action_dispatch/routing/endpoint.rb +9 -2
  128. data/lib/action_dispatch/routing/inspector.rb +58 -67
  129. data/lib/action_dispatch/routing/mapper.rb +733 -447
  130. data/lib/action_dispatch/routing/polymorphic_routes.rb +161 -139
  131. data/lib/action_dispatch/routing/redirection.rb +36 -26
  132. data/lib/action_dispatch/routing/route_set.rb +321 -291
  133. data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
  134. data/lib/action_dispatch/routing/url_for.rb +65 -25
  135. data/lib/action_dispatch/routing.rb +17 -18
  136. data/lib/action_dispatch/system_test_case.rb +147 -0
  137. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  138. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  139. data/lib/action_dispatch/system_testing/server.rb +31 -0
  140. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  141. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  142. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  143. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  144. data/lib/action_dispatch/testing/assertions/response.rb +45 -20
  145. data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
  146. data/lib/action_dispatch/testing/assertions.rb +6 -4
  147. data/lib/action_dispatch/testing/integration.rb +347 -209
  148. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  149. data/lib/action_dispatch/testing/test_process.rb +28 -22
  150. data/lib/action_dispatch/testing/test_request.rb +27 -34
  151. data/lib/action_dispatch/testing/test_response.rb +35 -7
  152. data/lib/action_dispatch.rb +27 -19
  153. data/lib/action_pack/gem_version.rb +5 -3
  154. data/lib/action_pack/version.rb +3 -1
  155. data/lib/action_pack.rb +4 -2
  156. metadata +56 -38
  157. data/lib/action_controller/metal/hide_actions.rb +0 -40
  158. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  159. data/lib/action_controller/middleware.rb +0 -39
  160. data/lib/action_controller/model_naming.rb +0 -12
  161. data/lib/action_dispatch/journey/backwards.rb +0 -5
  162. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  163. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  164. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  165. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  166. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,28 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/inflector/methods"
2
4
  require "active_support/dependencies"
3
5
 
4
6
  module ActionDispatch
5
7
  class MiddlewareStack
6
8
  class Middleware
7
- attr_reader :args, :block, :name, :classcache
8
-
9
- def initialize(klass_or_name, *args, &block)
10
- @klass = nil
11
-
12
- if klass_or_name.respond_to?(:name)
13
- @klass = klass_or_name
14
- @name = @klass.name
15
- else
16
- @name = klass_or_name.to_s
17
- end
9
+ attr_reader :args, :block, :klass
18
10
 
19
- @classcache = ActiveSupport::Dependencies::Reference
20
- @args, @block = args, block
11
+ def initialize(klass, args, block)
12
+ @klass = klass
13
+ @args = args
14
+ @block = block
21
15
  end
22
16
 
23
- def klass
24
- @klass || classcache[@name]
25
- end
17
+ def name; klass.name; end
26
18
 
27
19
  def ==(middleware)
28
20
  case middleware
@@ -30,24 +22,20 @@ module ActionDispatch
30
22
  klass == middleware.klass
31
23
  when Class
32
24
  klass == middleware
33
- else
34
- normalize(@name) == normalize(middleware)
35
25
  end
36
26
  end
37
27
 
38
28
  def inspect
39
- klass.to_s
29
+ if klass.is_a?(Class)
30
+ klass.to_s
31
+ else
32
+ klass.class.to_s
33
+ end
40
34
  end
41
35
 
42
36
  def build(app)
43
37
  klass.new(app, *args, &block)
44
38
  end
45
-
46
- private
47
-
48
- def normalize(object)
49
- object.to_s.strip.sub(/^::/, '')
50
- end
51
39
  end
52
40
 
53
41
  include Enumerable
@@ -75,19 +63,17 @@ module ActionDispatch
75
63
  middlewares[i]
76
64
  end
77
65
 
78
- def unshift(*args, &block)
79
- middleware = self.class::Middleware.new(*args, &block)
80
- middlewares.unshift(middleware)
66
+ def unshift(klass, *args, &block)
67
+ middlewares.unshift(build_middleware(klass, args, block))
81
68
  end
82
69
 
83
70
  def initialize_copy(other)
84
71
  self.middlewares = other.middlewares.dup
85
72
  end
86
73
 
87
- def insert(index, *args, &block)
74
+ def insert(index, klass, *args, &block)
88
75
  index = assert_index(index, :before)
89
- middleware = self.class::Middleware.new(*args, &block)
90
- middlewares.insert(index, middleware)
76
+ middlewares.insert(index, build_middleware(klass, args, block))
91
77
  end
92
78
 
93
79
  alias_method :insert_before, :insert
@@ -104,26 +90,27 @@ module ActionDispatch
104
90
  end
105
91
 
106
92
  def delete(target)
107
- middlewares.delete target
93
+ middlewares.delete_if { |m| m.klass == target }
108
94
  end
109
95
 
110
- def use(*args, &block)
111
- middleware = self.class::Middleware.new(*args, &block)
112
- middlewares.push(middleware)
96
+ def use(klass, *args, &block)
97
+ middlewares.push(build_middleware(klass, args, block))
113
98
  end
114
99
 
115
100
  def build(app = nil, &block)
116
- app ||= block
117
- raise "MiddlewareStack#build requires an app" unless app
118
- middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }
101
+ middlewares.freeze.reverse.inject(app || block) { |a, e| e.build(a) }
119
102
  end
120
103
 
121
- protected
104
+ private
122
105
 
123
- def assert_index(index, where)
124
- i = index.is_a?(Integer) ? index : middlewares.index(index)
125
- raise "No such middleware to insert #{where}: #{index.inspect}" unless i
126
- i
127
- end
106
+ def assert_index(index, where)
107
+ i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index }
108
+ raise "No such middleware to insert #{where}: #{index.inspect}" unless i
109
+ i
110
+ end
111
+
112
+ def build_middleware(klass, args, block)
113
+ Middleware.new(klass, args, block)
114
+ end
128
115
  end
129
116
  end
@@ -1,35 +1,41 @@
1
- require 'rack/utils'
2
- require 'active_support/core_ext/uri'
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/utils"
4
+ require "active_support/core_ext/uri"
3
5
 
4
6
  module ActionDispatch
5
7
  # This middleware returns a file's contents from disk in the body response.
6
- # When initialized it can accept an optional 'Cache-Control' header which
7
- # will be set when a response containing a file's contents is delivered.
8
+ # When initialized, it can accept optional HTTP headers, which will be set
9
+ # when a response containing a file's contents is delivered.
8
10
  #
9
- # This middleware will render the file specified in `env["PATH_INFO"]`
10
- # where the base path is in the +root+ directory. For example if the +root+
11
- # is set to `public/` then a request with `env["PATH_INFO"]` of
12
- # `assets/application.js` will return a response with contents of a file
13
- # located at `public/assets/application.js` if the file exists. If the file
14
- # does not exist a 404 "File not Found" response will be returned.
11
+ # This middleware will render the file specified in <tt>env["PATH_INFO"]</tt>
12
+ # where the base path is in the +root+ directory. For example, if the +root+
13
+ # is set to +public/+, then a request with <tt>env["PATH_INFO"]</tt> of
14
+ # +assets/application.js+ will return a response with the contents of a file
15
+ # located at +public/assets/application.js+ if the file exists. If the file
16
+ # does not exist, a 404 "File not Found" response will be returned.
15
17
  class FileHandler
16
- def initialize(root, cache_control)
17
- @root = root.chomp('/')
18
- @compiled_root = /^#{Regexp.escape(root)}/
19
- headers = cache_control && { 'Cache-Control' => cache_control }
20
- @file_server = ::Rack::File.new(@root, headers)
18
+ def initialize(root, index: "index", headers: {})
19
+ @root = root.chomp("/").b
20
+ @file_server = ::Rack::File.new(@root, headers)
21
+ @index = index
21
22
  end
22
23
 
24
+ # Takes a path to a file. If the file is found, has valid encoding, and has
25
+ # correct read permissions, the return value is a URI-escaped string
26
+ # representing the filename. Otherwise, false is returned.
27
+ #
28
+ # Used by the +Static+ class to check the existence of a valid file
29
+ # in the server's +public/+ directory (see Static#call).
23
30
  def match?(path)
24
- path = URI.parser.unescape(path)
25
- return false unless valid_path?(path)
31
+ path = ::Rack::Utils.unescape_path path
32
+ return false unless ::Rack::Utils.valid_path? path
33
+ path = ::Rack::Utils.clean_path_info path
26
34
 
27
- paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"].map { |v|
28
- Rack::Utils.clean_path_info v
29
- }
35
+ paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"]
30
36
 
31
37
  if match = paths.detect { |p|
32
- path = File.join(@root, p.force_encoding('UTF-8'))
38
+ path = File.join(@root, p.b)
33
39
  begin
34
40
  File.file?(path) && File.readable?(path)
35
41
  rescue SystemCallError
@@ -37,31 +43,35 @@ module ActionDispatch
37
43
  end
38
44
 
39
45
  }
40
- return ::Rack::Utils.escape(match)
46
+ return ::Rack::Utils.escape_path(match).b
41
47
  end
42
48
  end
43
49
 
44
50
  def call(env)
45
- path = env['PATH_INFO']
51
+ serve(Rack::Request.new(env))
52
+ end
53
+
54
+ def serve(request)
55
+ path = request.path_info
46
56
  gzip_path = gzip_file_path(path)
47
57
 
48
- if gzip_path && gzip_encoding_accepted?(env)
49
- env['PATH_INFO'] = gzip_path
50
- status, headers, body = @file_server.call(env)
58
+ if gzip_path && gzip_encoding_accepted?(request)
59
+ request.path_info = gzip_path
60
+ status, headers, body = @file_server.call(request.env)
51
61
  if status == 304
52
62
  return [status, headers, body]
53
63
  end
54
- headers['Content-Encoding'] = 'gzip'
55
- headers['Content-Type'] = content_type(path)
64
+ headers["Content-Encoding"] = "gzip"
65
+ headers["Content-Type"] = content_type(path)
56
66
  else
57
- status, headers, body = @file_server.call(env)
67
+ status, headers, body = @file_server.call(request.env)
58
68
  end
59
69
 
60
- headers['Vary'] = 'Accept-Encoding' if gzip_path
70
+ headers["Vary"] = "Accept-Encoding" if gzip_path
61
71
 
62
72
  return [status, headers, body]
63
73
  ensure
64
- env['PATH_INFO'] = path
74
+ request.path_info = path
65
75
  end
66
76
 
67
77
  private
@@ -70,54 +80,51 @@ module ActionDispatch
70
80
  end
71
81
 
72
82
  def content_type(path)
73
- ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
83
+ ::Rack::Mime.mime_type(::File.extname(path), "text/plain".freeze)
74
84
  end
75
85
 
76
- def gzip_encoding_accepted?(env)
77
- env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/i
86
+ def gzip_encoding_accepted?(request)
87
+ request.accept_encoding.any? { |enc, quality| enc =~ /\bgzip\b/i }
78
88
  end
79
89
 
80
90
  def gzip_file_path(path)
81
91
  can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
82
92
  gzip_path = "#{path}.gz"
83
- if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape(gzip_path)))
84
- gzip_path
93
+ if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path).b))
94
+ gzip_path.b
85
95
  else
86
96
  false
87
97
  end
88
98
  end
89
-
90
- def valid_path?(path)
91
- path.valid_encoding? && !path.include?("\0")
92
- end
93
99
  end
94
100
 
95
101
  # This middleware will attempt to return the contents of a file's body from
96
- # disk in the response. If a file is not found on disk, the request will be
102
+ # disk in the response. If a file is not found on disk, the request will be
97
103
  # delegated to the application stack. This middleware is commonly initialized
98
- # to serve assets from a server's `public/` directory.
104
+ # to serve assets from a server's +public/+ directory.
99
105
  #
100
106
  # This middleware verifies the path to ensure that only files
101
107
  # living in the root directory can be rendered. A request cannot
102
108
  # produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
103
109
  # requests will result in a file being returned.
104
110
  class Static
105
- def initialize(app, path, cache_control=nil)
111
+ def initialize(app, path, index: "index", headers: {})
106
112
  @app = app
107
- @file_handler = FileHandler.new(path, cache_control)
113
+ @file_handler = FileHandler.new(path, index: index, headers: headers)
108
114
  end
109
115
 
110
116
  def call(env)
111
- case env['REQUEST_METHOD']
112
- when 'GET', 'HEAD'
113
- path = env['PATH_INFO'].chomp('/')
117
+ req = Rack::Request.new env
118
+
119
+ if req.get? || req.head?
120
+ path = req.path_info.chomp("/".freeze)
114
121
  if match = @file_handler.match?(path)
115
- env["PATH_INFO"] = match
116
- return @file_handler.call(env)
122
+ req.path_info = match
123
+ return @file_handler.serve(req)
117
124
  end
118
125
  end
119
126
 
120
- @app.call(env)
127
+ @app.call(req.env)
121
128
  end
122
129
  end
123
130
  end
@@ -5,20 +5,8 @@
5
5
  <pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
6
6
  <% end %>
7
7
 
8
- <%
9
- clean_params = @request.filtered_parameters.clone
10
- clean_params.delete("action")
11
- clean_params.delete("controller")
12
-
13
- request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
14
-
15
- def debug_hash(object)
16
- object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
17
- end unless self.class.method_defined?(:debug_hash)
18
- %>
19
-
20
8
  <h2 style="margin-top: 30px">Request</h2>
21
- <p><b>Parameters</b>:</p> <pre><%= request_dump %></pre>
9
+ <p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
22
10
 
23
11
  <div class="details">
24
12
  <div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
@@ -31,4 +19,4 @@
31
19
  </div>
32
20
 
33
21
  <h2 style="margin-top: 30px">Response</h2>
34
- <p><b>Headers</b>:</p> <pre><%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre>
22
+ <p><b>Headers</b>:</p> <pre><%= debug_headers(defined?(@response) ? @response.headers : {}) %></pre>
@@ -0,0 +1,8 @@
1
+ <% @source_extracts.first(3).each do |source_extract| %>
2
+ <% if source_extract[:code] %>
3
+ Extracted source (around line #<%= source_extract[:line_number] %>):
4
+
5
+ <% source_extract[:code].each do |line, source| -%>
6
+ <%= line == source_extract[:line_number] ? "*#{line}" : "##{line}" -%> <%= source -%><% end -%>
7
+ <% end %>
8
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <header>
2
+ <h1>
3
+ <%= @exception.class.to_s %>
4
+ <% if @request.parameters['controller'] %>
5
+ in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
6
+ <% end %>
7
+ </h1>
8
+ </header>
9
+
10
+ <div id="container">
11
+ <h2>
12
+ <%= h @exception.message %>
13
+ <% if %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}.match?(@exception.message) %>
14
+ <br />To resolve this issue run: bin/rails active_storage:install
15
+ <% end %>
16
+ </h2>
17
+
18
+ <%= render template: "rescues/_source" %>
19
+ <%= render template: "rescues/_trace" %>
20
+ <%= render template: "rescues/_request_and_response" %>
21
+ </div>
@@ -0,0 +1,13 @@
1
+ <%= @exception.class.to_s %><%
2
+ if @request.parameters['controller']
3
+ %> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
4
+ <% end %>
5
+
6
+ <%= @exception.message %>
7
+ <% if %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}.match?(@exception.message) %>
8
+ To resolve this issue run: bin/rails active_storage:install
9
+ <% end %>
10
+
11
+ <%= render template: "rescues/_source" %>
12
+ <%= render template: "rescues/_trace" %>
13
+ <%= render template: "rescues/_request_and_response" %>
@@ -106,6 +106,7 @@
106
106
 
107
107
  .line {
108
108
  padding-left: 10px;
109
+ white-space: pre;
109
110
  }
110
111
 
111
112
  .line:hover {
@@ -1,6 +1,6 @@
1
1
  <header>
2
2
  <h1>
3
- <%= @exception.original_exception.class.to_s %> in
3
+ <%= @exception.cause.class.to_s %> in
4
4
  <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
5
5
  </h1>
6
6
  </header>
@@ -1,4 +1,4 @@
1
- <%= @exception.original_exception.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
1
+ <%= @exception.cause.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
2
2
 
3
3
  Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised:
4
4
  <%= @exception.message %>
@@ -4,13 +4,13 @@
4
4
  <%= route[:name] %><span class='helper'>_path</span>
5
5
  <% end %>
6
6
  </td>
7
- <td data-route-verb='<%= route[:verb] %>'>
7
+ <td>
8
8
  <%= route[:verb] %>
9
9
  </td>
10
- <td data-route-path='<%= route[:path] %>' data-regexp='<%= route[:regexp] %>'>
10
+ <td data-route-path='<%= route[:path] %>'>
11
11
  <%= route[:path] %>
12
12
  </td>
13
- <td data-route-reqs='<%= route[:reqs] %>'>
14
- <%= route[:reqs] %>
13
+ <td>
14
+ <%=simple_format route[:reqs] %>
15
15
  </td>
16
16
  </tr>
@@ -17,6 +17,10 @@
17
17
  line-height: 15px;
18
18
  }
19
19
 
20
+ #route_table thead tr.bottom th input#search {
21
+ -webkit-appearance: textfield;
22
+ }
23
+
20
24
  #route_table tbody tr {
21
25
  border-bottom: 1px solid #ddd;
22
26
  }
@@ -60,7 +64,7 @@
60
64
  <%= link_to "Path", "#", 'data-route-helper' => '_path',
61
65
  title: "Returns a relative path (without the http or domain)" %> /
62
66
  <%= link_to "Url", "#", 'data-route-helper' => '_url',
63
- title: "Returns an absolute url (with the http and domain)" %>
67
+ title: "Returns an absolute URL (with the http and domain)" %>
64
68
  </th>
65
69
  <th><%# HTTP Verb %>
66
70
  </th>
@@ -81,92 +85,87 @@
81
85
  </table>
82
86
 
83
87
  <script type='text/javascript'>
84
- // Iterates each element through a function
85
- function each(elems, func) {
86
- if (!elems instanceof Array) { elems = [elems]; }
87
- for (var i = 0, len = elems.length; i < len; i++) {
88
- func(elems[i]);
89
- }
90
- }
91
-
92
- // Sets innerHTML for an element
93
- function setContent(elem, text) {
94
- elem.innerHTML = text;
95
- }
88
+ // support forEarch iterator on NodeList
89
+ NodeList.prototype.forEach = Array.prototype.forEach;
96
90
 
97
91
  // Enables path search functionality
98
92
  function setupMatchPaths() {
99
- // Check if the user input (sanitized as a path) matches the regexp data attribute
100
- function checkExactMatch(section, elem, value) {
101
- var string = sanitizePath(value),
102
- regexp = elem.getAttribute("data-regexp");
103
-
104
- showMatch(string, regexp, section, elem);
105
- }
106
-
107
- // Check if the route path data attribute contains the user input
108
- function checkFuzzyMatch(section, elem, value) {
109
- var string = elem.getAttribute("data-route-path"),
110
- regexp = value;
111
-
112
- showMatch(string, regexp, section, elem);
93
+ // Check if there are any matched results in a section
94
+ function checkNoMatch(section, noMatchText) {
95
+ if (section.children.length <= 1) {
96
+ section.innerHTML += noMatchText;
97
+ }
113
98
  }
114
99
 
115
- // Display the parent <tr> element in the appropriate section when there's a match
116
- function showMatch(string, regexp, section, elem) {
117
- if(string.match(RegExp(regexp))) {
118
- section.appendChild(elem.parentNode.cloneNode(true));
119
- }
100
+ // get JSON from URL and invoke callback with result
101
+ function getJSON(url, success) {
102
+ var xhr = new XMLHttpRequest();
103
+ xhr.open('GET', url);
104
+ xhr.onload = function() {
105
+ if (this.status == 200)
106
+ success(JSON.parse(this.response));
107
+ };
108
+ xhr.send();
120
109
  }
121
110
 
122
- // Check if there are any matched results in a section
123
- function checkNoMatch(section, defaultText, noMatchText) {
124
- if (section.innerHTML === defaultText) {
125
- setContent(section, defaultText + noMatchText);
111
+ function delayedKeyup(input, callback) {
112
+ var timeout;
113
+ input.onkeyup = function(){
114
+ if (timeout) clearTimeout(timeout);
115
+ timeout = setTimeout(callback, 300);
126
116
  }
127
117
  }
128
118
 
129
- // Ensure path always starts with a slash "/" and remove params or fragments
119
+ // remove params or fragments
130
120
  function sanitizePath(path) {
131
- var path = path.charAt(0) == '/' ? path : "/" + path;
132
- return path.replace(/\#.*|\?.*/, '');
121
+ return path.replace(/[#?].*/, '');
133
122
  }
134
123
 
135
- var regexpElems = document.querySelectorAll('#route_table [data-regexp]'),
136
- searchElem = document.querySelector('#search'),
137
- exactMatches = document.querySelector('#exact_matches'),
138
- fuzzyMatches = document.querySelector('#fuzzy_matches');
124
+ var pathElements = document.querySelectorAll('#route_table [data-route-path]'),
125
+ searchElem = document.querySelector('#search'),
126
+ exactSection = document.querySelector('#exact_matches'),
127
+ fuzzySection = document.querySelector('#fuzzy_matches');
139
128
 
140
129
  // Remove matches when no search value is present
141
130
  searchElem.onblur = function(e) {
142
131
  if (searchElem.value === "") {
143
- setContent(exactMatches, "");
144
- setContent(fuzzyMatches, "");
132
+ exactSection.innerHTML = "";
133
+ fuzzySection.innerHTML = "";
145
134
  }
146
135
  }
147
136
 
148
137
  // On key press perform a search for matching paths
149
- searchElem.onkeyup = function(e){
150
- var userInput = searchElem.value,
151
- defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + escape(sanitizePath(userInput)) +'):</th></tr>',
152
- defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + escape(userInput) +'):</th></tr>',
138
+ delayedKeyup(searchElem, function() {
139
+ var path = sanitizePath(searchElem.value),
140
+ defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + path +'):</th></tr>',
141
+ defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + path +'):</th></tr>',
153
142
  noExactMatch = '<tr><th colspan="4">No Exact Matches Found</th></tr>',
154
143
  noFuzzyMatch = '<tr><th colspan="4">No Fuzzy Matches Found</th></tr>';
155
144
 
156
- // Clear out results section
157
- setContent(exactMatches, defaultExactMatch);
158
- setContent(fuzzyMatches, defaultFuzzyMatch);
145
+ if (!path)
146
+ return searchElem.onblur();
159
147
 
160
- // Display exact matches and fuzzy matches
161
- each(regexpElems, function(elem) {
162
- checkExactMatch(exactMatches, elem, userInput);
163
- checkFuzzyMatch(fuzzyMatches, elem, userInput);
164
- })
148
+ getJSON('/rails/info/routes?path=' + path, function(matches){
149
+ // Clear out results section
150
+ exactSection.innerHTML = defaultExactMatch;
151
+ fuzzySection.innerHTML = defaultFuzzyMatch;
165
152
 
166
- // Display 'No Matches' message when no matches are found
167
- checkNoMatch(exactMatches, defaultExactMatch, noExactMatch);
168
- checkNoMatch(fuzzyMatches, defaultFuzzyMatch, noFuzzyMatch);
169
- }
153
+ // Display exact matches and fuzzy matches
154
+ pathElements.forEach(function(elem) {
155
+ var elemPath = elem.getAttribute('data-route-path');
156
+
157
+ if (matches['exact'].indexOf(elemPath) != -1)
158
+ exactSection.appendChild(elem.parentNode.cloneNode(true));
159
+
160
+ if (matches['fuzzy'].indexOf(elemPath) != -1)
161
+ fuzzySection.appendChild(elem.parentNode.cloneNode(true));
162
+ })
163
+
164
+ // Display 'No Matches' message when no matches are found
165
+ checkNoMatch(exactSection, noExactMatch);
166
+ checkNoMatch(fuzzySection, noFuzzyMatch);
167
+ })
168
+ })
170
169
  }
171
170
 
172
171
  // Enables functionality to toggle between `_path` and `_url` helper suffixes
@@ -174,19 +173,20 @@
174
173
 
175
174
  // Sets content for each element
176
175
  function setValOn(elems, val) {
177
- each(elems, function(elem) {
178
- setContent(elem, val);
176
+ elems.forEach(function(elem) {
177
+ elem.innerHTML = val;
179
178
  });
180
179
  }
181
180
 
182
181
  // Sets onClick event for each element
183
182
  function onClick(elems, func) {
184
- each(elems, function(elem) {
183
+ elems.forEach(function(elem) {
185
184
  elem.onclick = func;
186
185
  });
187
186
  }
188
187
 
189
188
  var toggleLinks = document.querySelectorAll('#route_table [data-route-helper]');
189
+
190
190
  onClick(toggleLinks, function(){
191
191
  var helperTxt = this.getAttribute("data-route-helper"),
192
192
  helperElems = document.querySelectorAll('[data-route-name] span.helper');