actionpack 6.1.7.5 → 7.1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +355 -435
  3. data/MIT-LICENSE +2 -1
  4. data/README.rdoc +6 -7
  5. data/lib/abstract_controller/asset_paths.rb +1 -1
  6. data/lib/abstract_controller/base.rb +33 -37
  7. data/lib/abstract_controller/caching/fragments.rb +4 -2
  8. data/lib/abstract_controller/caching.rb +1 -1
  9. data/lib/abstract_controller/callbacks.rb +50 -11
  10. data/lib/abstract_controller/collector.rb +2 -2
  11. data/lib/abstract_controller/deprecator.rb +7 -0
  12. data/lib/abstract_controller/error.rb +1 -1
  13. data/lib/abstract_controller/helpers.rb +78 -30
  14. data/lib/abstract_controller/logger.rb +1 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
  16. data/lib/abstract_controller/rendering.rb +12 -14
  17. data/lib/abstract_controller/translation.rb +26 -7
  18. data/lib/abstract_controller/url_for.rb +6 -6
  19. data/lib/abstract_controller.rb +6 -0
  20. data/lib/action_controller/api.rb +12 -10
  21. data/lib/action_controller/base.rb +8 -21
  22. data/lib/action_controller/caching.rb +2 -0
  23. data/lib/action_controller/deprecator.rb +7 -0
  24. data/lib/action_controller/form_builder.rb +4 -2
  25. data/lib/action_controller/log_subscriber.rb +20 -7
  26. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  27. data/lib/action_controller/metal/conditional_get.rb +137 -102
  28. data/lib/action_controller/metal/content_security_policy.rb +37 -3
  29. data/lib/action_controller/metal/cookies.rb +1 -1
  30. data/lib/action_controller/metal/data_streaming.rb +25 -31
  31. data/lib/action_controller/metal/default_headers.rb +2 -0
  32. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  34. data/lib/action_controller/metal/exceptions.rb +27 -30
  35. data/lib/action_controller/metal/flash.rb +6 -2
  36. data/lib/action_controller/metal/head.rb +9 -7
  37. data/lib/action_controller/metal/helpers.rb +5 -16
  38. data/lib/action_controller/metal/http_authentication.rb +78 -42
  39. data/lib/action_controller/metal/implicit_render.rb +5 -3
  40. data/lib/action_controller/metal/instrumentation.rb +62 -50
  41. data/lib/action_controller/metal/live.rb +67 -2
  42. data/lib/action_controller/metal/mime_responds.rb +5 -5
  43. data/lib/action_controller/metal/params_wrapper.rb +24 -13
  44. data/lib/action_controller/metal/permissions_policy.rb +20 -29
  45. data/lib/action_controller/metal/redirecting.rb +96 -23
  46. data/lib/action_controller/metal/renderers.rb +14 -15
  47. data/lib/action_controller/metal/rendering.rb +121 -16
  48. data/lib/action_controller/metal/request_forgery_protection.rb +208 -68
  49. data/lib/action_controller/metal/rescue.rb +7 -4
  50. data/lib/action_controller/metal/streaming.rb +74 -36
  51. data/lib/action_controller/metal/strong_parameters.rb +254 -151
  52. data/lib/action_controller/metal/testing.rb +9 -2
  53. data/lib/action_controller/metal/url_for.rb +10 -5
  54. data/lib/action_controller/metal.rb +89 -34
  55. data/lib/action_controller/railtie.rb +66 -9
  56. data/lib/action_controller/renderer.rb +99 -85
  57. data/lib/action_controller/test_case.rb +42 -11
  58. data/lib/action_controller.rb +10 -6
  59. data/lib/action_dispatch/constants.rb +32 -0
  60. data/lib/action_dispatch/deprecator.rb +7 -0
  61. data/lib/action_dispatch/http/cache.rb +21 -16
  62. data/lib/action_dispatch/http/content_security_policy.rb +122 -44
  63. data/lib/action_dispatch/http/filter_parameters.rb +14 -23
  64. data/lib/action_dispatch/http/headers.rb +3 -1
  65. data/lib/action_dispatch/http/mime_negotiation.rb +25 -15
  66. data/lib/action_dispatch/http/mime_type.rb +43 -22
  67. data/lib/action_dispatch/http/mime_types.rb +3 -1
  68. data/lib/action_dispatch/http/parameters.rb +6 -6
  69. data/lib/action_dispatch/http/permissions_policy.rb +57 -19
  70. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  71. data/lib/action_dispatch/http/request.rb +75 -51
  72. data/lib/action_dispatch/http/response.rb +81 -77
  73. data/lib/action_dispatch/http/upload.rb +15 -2
  74. data/lib/action_dispatch/http/url.rb +11 -19
  75. data/lib/action_dispatch/journey/formatter.rb +8 -2
  76. data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
  79. data/lib/action_dispatch/journey/nodes/node.rb +70 -5
  80. data/lib/action_dispatch/journey/path/pattern.rb +36 -27
  81. data/lib/action_dispatch/journey/route.rb +8 -14
  82. data/lib/action_dispatch/journey/router/utils.rb +2 -2
  83. data/lib/action_dispatch/journey/router.rb +10 -9
  84. data/lib/action_dispatch/journey/routes.rb +5 -5
  85. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  86. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  87. data/lib/action_dispatch/log_subscriber.rb +23 -0
  88. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -7
  89. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  90. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  91. data/lib/action_dispatch/middleware/cookies.rb +97 -107
  92. data/lib/action_dispatch/middleware/debug_exceptions.rb +31 -28
  93. data/lib/action_dispatch/middleware/debug_locks.rb +7 -4
  94. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  95. data/lib/action_dispatch/middleware/exception_wrapper.rb +190 -27
  96. data/lib/action_dispatch/middleware/executor.rb +3 -0
  97. data/lib/action_dispatch/middleware/flash.rb +24 -18
  98. data/lib/action_dispatch/middleware/host_authorization.rb +19 -20
  99. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  100. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  101. data/lib/action_dispatch/middleware/remote_ip.rb +32 -19
  102. data/lib/action_dispatch/middleware/request_id.rb +5 -3
  103. data/lib/action_dispatch/middleware/server_timing.rb +76 -0
  104. data/lib/action_dispatch/middleware/session/abstract_store.rb +6 -1
  105. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  106. data/lib/action_dispatch/middleware/session/cookie_store.rb +19 -13
  107. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  108. data/lib/action_dispatch/middleware/show_exceptions.rb +30 -25
  109. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  110. data/lib/action_dispatch/middleware/stack.rb +34 -11
  111. data/lib/action_dispatch/middleware/static.rb +16 -16
  112. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  113. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +5 -5
  114. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
  115. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  116. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
  117. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +10 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -3
  119. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +9 -9
  120. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  121. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
  122. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +45 -18
  123. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -15
  124. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -4
  125. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +6 -6
  126. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +7 -7
  127. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  128. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  129. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -55
  131. data/lib/action_dispatch/railtie.rb +20 -4
  132. data/lib/action_dispatch/request/session.rb +59 -19
  133. data/lib/action_dispatch/request/utils.rb +8 -3
  134. data/lib/action_dispatch/routing/inspector.rb +55 -7
  135. data/lib/action_dispatch/routing/mapper.rb +117 -107
  136. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  137. data/lib/action_dispatch/routing/redirection.rb +20 -8
  138. data/lib/action_dispatch/routing/route_set.rb +67 -27
  139. data/lib/action_dispatch/routing/routes_proxy.rb +11 -16
  140. data/lib/action_dispatch/routing/url_for.rb +29 -26
  141. data/lib/action_dispatch/routing.rb +12 -13
  142. data/lib/action_dispatch/system_test_case.rb +8 -8
  143. data/lib/action_dispatch/system_testing/browser.rb +20 -29
  144. data/lib/action_dispatch/system_testing/driver.rb +34 -18
  145. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +35 -20
  146. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
  147. data/lib/action_dispatch/testing/assertion_response.rb +1 -1
  148. data/lib/action_dispatch/testing/assertions/response.rb +14 -7
  149. data/lib/action_dispatch/testing/assertions/routing.rb +70 -30
  150. data/lib/action_dispatch/testing/assertions.rb +3 -4
  151. data/lib/action_dispatch/testing/integration.rb +33 -25
  152. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  153. data/lib/action_dispatch/testing/test_process.rb +5 -30
  154. data/lib/action_dispatch/testing/test_request.rb +1 -1
  155. data/lib/action_dispatch/testing/test_response.rb +34 -2
  156. data/lib/action_dispatch.rb +38 -4
  157. data/lib/action_pack/gem_version.rb +4 -4
  158. data/lib/action_pack/version.rb +1 -1
  159. data/lib/action_pack.rb +1 -1
  160. metadata +67 -30
@@ -4,6 +4,11 @@ require "active_support/inflector/methods"
4
4
  require "active_support/dependencies"
5
5
 
6
6
  module ActionDispatch
7
+ # = Action Dispatch \MiddlewareStack
8
+ #
9
+ # Read more about {Rails middleware
10
+ # stack}[https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack]
11
+ # in the guides.
7
12
  class MiddlewareStack
8
13
  class Middleware
9
14
  attr_reader :args, :block, :klass
@@ -20,13 +25,13 @@ module ActionDispatch
20
25
  case middleware
21
26
  when Middleware
22
27
  klass == middleware.klass
23
- when Class
28
+ when Module
24
29
  klass == middleware
25
30
  end
26
31
  end
27
32
 
28
33
  def inspect
29
- if klass.is_a?(Class)
34
+ if klass.is_a?(Module)
30
35
  klass.to_s
31
36
  else
32
37
  klass.class.to_s
@@ -72,8 +77,8 @@ module ActionDispatch
72
77
  yield(self) if block_given?
73
78
  end
74
79
 
75
- def each
76
- @middlewares.each { |x| yield x }
80
+ def each(&block)
81
+ @middlewares.each(&block)
77
82
  end
78
83
 
79
84
  def size
@@ -91,7 +96,7 @@ module ActionDispatch
91
96
  def unshift(klass, *args, &block)
92
97
  middlewares.unshift(build_middleware(klass, args, block))
93
98
  end
94
- ruby2_keywords(:unshift) if respond_to?(:ruby2_keywords, true)
99
+ ruby2_keywords(:unshift)
95
100
 
96
101
  def initialize_copy(other)
97
102
  self.middlewares = other.middlewares.dup
@@ -101,7 +106,7 @@ module ActionDispatch
101
106
  index = assert_index(index, :before)
102
107
  middlewares.insert(index, build_middleware(klass, args, block))
103
108
  end
104
- ruby2_keywords(:insert) if respond_to?(:ruby2_keywords, true)
109
+ ruby2_keywords(:insert)
105
110
 
106
111
  alias_method :insert_before, :insert
107
112
 
@@ -109,17 +114,29 @@ module ActionDispatch
109
114
  index = assert_index(index, :after)
110
115
  insert(index + 1, *args, &block)
111
116
  end
112
- ruby2_keywords(:insert_after) if respond_to?(:ruby2_keywords, true)
117
+ ruby2_keywords(:insert_after)
113
118
 
114
119
  def swap(target, *args, &block)
115
120
  index = assert_index(target, :before)
116
121
  insert(index, *args, &block)
117
122
  middlewares.delete_at(index + 1)
118
123
  end
119
- ruby2_keywords(:swap) if respond_to?(:ruby2_keywords, true)
124
+ ruby2_keywords(:swap)
120
125
 
126
+ # Deletes a middleware from the middleware stack.
127
+ #
128
+ # Returns the array of middlewares not including the deleted item, or
129
+ # returns nil if the target is not found.
121
130
  def delete(target)
122
- middlewares.delete_if { |m| m.klass == target }
131
+ middlewares.reject! { |m| m.name == target.name }
132
+ end
133
+
134
+ # Deletes a middleware from the middleware stack.
135
+ #
136
+ # Returns the array of middlewares not including the deleted item, or
137
+ # raises +RuntimeError+ if the target is not found.
138
+ def delete!(target)
139
+ delete(target) || (raise "No such middleware to remove: #{target.inspect}")
123
140
  end
124
141
 
125
142
  def move(target, source)
@@ -143,7 +160,7 @@ module ActionDispatch
143
160
  def use(klass, *args, &block)
144
161
  middlewares.push(build_middleware(klass, args, block))
145
162
  end
146
- ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
163
+ ruby2_keywords(:use)
147
164
 
148
165
  def build(app = nil, &block)
149
166
  instrumenting = ActiveSupport::Notifications.notifier.listening?(InstrumentationProxy::EVENT_NAME)
@@ -158,7 +175,7 @@ module ActionDispatch
158
175
 
159
176
  private
160
177
  def assert_index(index, where)
161
- i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index }
178
+ i = index.is_a?(Integer) ? index : index_of(index)
162
179
  raise "No such middleware to insert #{where}: #{index.inspect}" unless i
163
180
  i
164
181
  end
@@ -166,5 +183,11 @@ module ActionDispatch
166
183
  def build_middleware(klass, args, block)
167
184
  Middleware.new(klass, args, block)
168
185
  end
186
+
187
+ def index_of(klass)
188
+ middlewares.index do |m|
189
+ m.name == klass.name
190
+ end
191
+ end
169
192
  end
170
193
  end
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rack/utils"
4
- require "active_support/core_ext/uri"
5
4
 
6
5
  module ActionDispatch
6
+ # = Action Dispatch \Static
7
+ #
7
8
  # This middleware serves static files from disk, if available.
8
9
  # If no file is found, it hands off to the main app.
9
10
  #
10
- # In Rails apps, this middleware is configured to serve assets from
11
+ # In \Rails apps, this middleware is configured to serve assets from
11
12
  # the +public/+ directory.
12
13
  #
13
14
  # Only GET and HEAD requests are served. POST and other HTTP methods
@@ -25,22 +26,24 @@ module ActionDispatch
25
26
  end
26
27
  end
27
28
 
28
- # This endpoint serves static files from disk using Rack::File.
29
+ # = Action Dispatch \FileHandler
30
+ #
31
+ # This endpoint serves static files from disk using +Rack::Files+.
29
32
  #
30
33
  # URL paths are matched with static files according to expected
31
34
  # conventions: +path+, +path+.html, +path+/index.html.
32
35
  #
33
36
  # Precompressed versions of these files are checked first. Brotli (.br)
34
37
  # and gzip (.gz) files are supported. If +path+.br exists, this
35
- # endpoint returns that file with a <tt>Content-Encoding: br</tt> header.
38
+ # endpoint returns that file with a <tt>content-encoding: br</tt> header.
36
39
  #
37
- # If no matching file is found, this endpoint responds 404 Not Found.
40
+ # If no matching file is found, this endpoint responds <tt>404 Not Found</tt>.
38
41
  #
39
42
  # Pass the +root+ directory to search for matching files, an optional
40
43
  # <tt>index: "index"</tt> to change the default +path+/index.html, and optional
41
44
  # additional response headers.
42
45
  class FileHandler
43
- # Accept-Encoding value -> file extension
46
+ # +Accept-Encoding+ value -> file extension
44
47
  PRECOMPRESSED = {
45
48
  "br" => ".br",
46
49
  "gzip" => ".gz",
@@ -54,7 +57,7 @@ module ActionDispatch
54
57
  @precompressed = Array(precompressed).map(&:to_s) | %w[ identity ]
55
58
  @compressible_content_types = compressible_content_types
56
59
 
57
- @file_server = ::Rack::File.new(@root, headers)
60
+ @file_server = ::Rack::Files.new(@root, headers)
58
61
  end
59
62
 
60
63
  def call(env)
@@ -77,7 +80,7 @@ module ActionDispatch
77
80
  request.path_info, ::Rack::Utils.escape_path(filepath).b
78
81
 
79
82
  @file_server.call(request.env).tap do |status, headers, body|
80
- # Omit Content-Encoding/Type/etc headers for 304 Not Modified
83
+ # Omit content-encoding/type/etc headers for 304 Not Modified
81
84
  if status != 304
82
85
  headers.update(content_headers)
83
86
  end
@@ -105,7 +108,7 @@ module ActionDispatch
105
108
  end
106
109
 
107
110
  def try_files(filepath, content_type, accept_encoding:)
108
- headers = { "Content-Type" => content_type }
111
+ headers = { Rack::CONTENT_TYPE => content_type }
109
112
 
110
113
  if compressible? content_type
111
114
  try_precompressed_files filepath, headers, accept_encoding: accept_encoding
@@ -125,10 +128,10 @@ module ActionDispatch
125
128
  if content_encoding == "identity"
126
129
  return precompressed_filepath, headers
127
130
  else
128
- headers["Vary"] = "Accept-Encoding"
131
+ headers[ActionDispatch::Constants::VARY] = "accept-encoding"
129
132
 
130
133
  if accept_encoding.any? { |enc, _| /\b#{content_encoding}\b/i.match?(enc) }
131
- headers["Content-Encoding"] = content_encoding
134
+ headers[ActionDispatch::Constants::CONTENT_ENCODING] = content_encoding
132
135
  return precompressed_filepath, headers
133
136
  end
134
137
  end
@@ -137,11 +140,8 @@ module ActionDispatch
137
140
  end
138
141
 
139
142
  def file_readable?(path)
140
- file_stat = File.stat(File.join(@root, path.b))
141
- rescue SystemCallError
142
- false
143
- else
144
- file_stat.file? && file_stat.readable?
143
+ file_path = File.join(@root, path.b)
144
+ File.file?(file_path) && File.readable?(file_path)
145
145
  end
146
146
 
147
147
  def compressible?(content_type)
@@ -1,10 +1,10 @@
1
- <% actions = ActiveSupport::ActionableError.actions(exception) %>
1
+ <% actions = exception_wrapper.actions %>
2
2
 
3
3
  <% if actions.any? %>
4
4
  <div class="actions">
5
5
  <% actions.each do |action, _| %>
6
6
  <%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: {
7
- error: exception.class.name,
7
+ error: exception_wrapper.exception_class_name,
8
8
  action: action,
9
9
  location: request.path
10
10
  } %>
@@ -1,22 +1,22 @@
1
- <% if exception.respond_to?(:original_message) && exception.respond_to?(:corrections) %>
1
+ <% if exception_wrapper.has_corrections? %>
2
2
  <div class="exception-message">
3
- <%= simple_format h(exception.original_message), { class: "message" }, wrapper_tag: "div" %>
3
+ <%= simple_format h(exception_wrapper.original_message), { class: "message" }, wrapper_tag: "div" %>
4
4
  </div>
5
5
  <%
6
6
  # The 'did_you_mean' gem can raise exceptions when calling #corrections on
7
7
  # the exception. If it does there are no corrections to show.
8
- corrections = exception.corrections rescue []
8
+ corrections = exception_wrapper.corrections rescue []
9
9
  %>
10
10
  <% if corrections.any? %>
11
11
  <b>Did you mean?</b>
12
12
  <ul>
13
13
  <% corrections.each do |correction| %>
14
- <li style="list-style-type: none"><%= h correction %></li>
14
+ <li class="correction"><%= h correction %></li>
15
15
  <% end %>
16
16
  </ul>
17
17
  <% end %>
18
18
  <% else %>
19
19
  <div class="exception-message">
20
- <%= simple_format h(exception.message), { class: "message" }, wrapper_tag: "div" %>
20
+ <%= simple_format h(exception_wrapper.message), { class: "message" }, wrapper_tag: "div" %>
21
21
  </div>
22
22
  <% end %>
@@ -1,24 +1,17 @@
1
- <% unless @exception.blamed_files.blank? %>
2
- <% if (hide = @exception.blamed_files.length > 8) %>
3
- <a href="#" onclick="return toggleTrace()">Toggle blamed files</a>
4
- <% end %>
5
- <pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
6
- <% end %>
7
-
8
- <h2 style="margin-top: 30px">Request</h2>
1
+ <h2 class="request-heading">Request</h2>
9
2
  <% if params_valid? %>
10
3
  <p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
11
4
  <% end %>
12
5
 
13
6
  <div class="details">
14
7
  <div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
15
- <div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>
8
+ <div id="session_dump" class="hidden"><pre><%= debug_hash @request.session %></pre></div>
16
9
  </div>
17
10
 
18
11
  <div class="details">
19
12
  <div class="summary"><a href="#" onclick="return toggleEnvDump()">Toggle env dump</a></div>
20
- <div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
13
+ <div id="env_dump" class="hidden"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
21
14
  </div>
22
15
 
23
- <h2 style="margin-top: 30px">Response</h2>
16
+ <h2 class="response-heading">Response</h2>
24
17
  <p><b>Headers</b>:</p> <pre><%= debug_headers(defined?(@response) ? @response.headers : {}) %></pre>
@@ -18,12 +18,19 @@
18
18
  </td>
19
19
  <td width="100%">
20
20
  <pre>
21
- <% source_extract[:code].each do |line, source| -%><div class="line<%= " active" if line == source_extract[:line_number] -%>"><%= source -%></div><% end -%>
21
+ <% source_extract[:code].each do |line, source| -%>
22
+ <div class="line<%= " active" if line == source_extract[:line_number] -%>"><% if source.is_a?(Array) -%><%= source[0] -%><span class="error_highlight"><%= source[1] -%></span><%= source[2] -%>
23
+ <% else -%>
24
+ <%= source -%>
25
+ <% end -%></div><% end -%>
22
26
  </pre>
23
27
  </td>
24
28
  </tr>
25
29
  </table>
26
30
  </div>
31
+ <%- unless self.error_highlight_available? -%>
32
+ <p class="error_highlight_tip">Tip: You may want to add <code>gem 'error_highlight', '&gt;= 0.4.0'</code> into your Gemfile, which will display the fine-grained error location.</p>
33
+ <%- end -%>
27
34
  </div>
28
35
  <% end %>
29
36
  <% end %>
@@ -14,7 +14,7 @@
14
14
 
15
15
  <% traces.each do |name, trace| %>
16
16
  <div id="<%= "#{name.gsub(/\s/, '-')}-#{error_index}" %>" style="display: <%= (name == trace_to_show) ? 'block' : 'none' %>;">
17
- <code style="font-size: 11px;">
17
+ <code class="traces">
18
18
  <% trace.each do |frame| %>
19
19
  <a class="trace-frames trace-frames-<%= error_index %>" data-exception-object-id="<%= frame[:exception_object_id] %>" data-frame-id="<%= frame[:id] %>" href="#">
20
20
  <%= frame[:trace] %>
@@ -25,7 +25,7 @@
25
25
  </div>
26
26
  <% end %>
27
27
 
28
- <script type="text/javascript">
28
+ <script>
29
29
  (function() {
30
30
  var traceFrames = document.getElementsByClassName('trace-frames-<%= error_index %>');
31
31
  var selectedFrame, currentSource = document.getElementById('frame-source-<%= error_index %>-0');
@@ -1,7 +1,12 @@
1
1
  <header>
2
- <h1>Blocked host: <%= @host %></h1>
2
+ <h1>Blocked hosts: <%= @hosts.join(", ") %></h1>
3
3
  </header>
4
- <div id="container">
5
- <h2>To allow requests to <%= @host %> make sure it is a valid hostname (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:</h2>
6
- <pre>config.hosts &lt;&lt; "<%= @host %>"</pre>
7
- </div>
4
+ <main role="main" id="container">
5
+ <h2>To allow requests to these hosts, make sure they are valid hostnames (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:</h2>
6
+ <pre>
7
+ <% @hosts.each do |host| %>
8
+ config.hosts &lt;&lt; "<%= host %>"
9
+ <% end %>
10
+ </pre>
11
+ <p>For more details view: <a href="https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization">the Host Authorization guide</a></p>
12
+ </main>
@@ -1,5 +1,9 @@
1
- Blocked host: <%= @host %>
1
+ Blocked hosts: <%= @hosts.join(", ") %>
2
2
 
3
- To allow requests to <%= @host %> make sure it is a valid hostname (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:
3
+ To allow requests to these hosts, make sure they are valid hostnames (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:
4
4
 
5
- config.hosts << "<%= @host %>"
5
+ <% @hosts.each do |host| %>
6
+ config.hosts << "<%= host %>"
7
+ <% end %>
8
+
9
+ For more details on host authorization view: https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization
@@ -1,35 +1,35 @@
1
1
  <header>
2
2
  <h1>
3
- <%= @exception.class.to_s %>
3
+ <%= @exception_wrapper.exception_class_name %>
4
4
  <% if params_valid? && @request.parameters['controller'] %>
5
5
  in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
6
6
  <% end %>
7
7
  </h1>
8
8
  </header>
9
9
 
10
- <div id="container">
11
- <%= render "rescues/message_and_suggestions", exception: @exception %>
12
- <%= render "rescues/actions", exception: @exception, request: @request %>
10
+ <main role="main" id="container">
11
+ <%= render "rescues/message_and_suggestions", exception: @exception, exception_wrapper: @exception_wrapper %>
12
+ <%= render "rescues/actions", exception: @exception, request: @request, exception_wrapper: @exception_wrapper %>
13
13
 
14
14
  <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx, error_index: 0 %>
15
15
  <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show, error_index: 0 %>
16
16
 
17
- <% if @exception.cause %>
17
+ <% if @exception_wrapper.has_cause? %>
18
18
  <h2>Exception Causes</h2>
19
19
  <% end %>
20
20
 
21
21
  <% @exception_wrapper.wrapped_causes.each.with_index(1) do |wrapper, index| %>
22
22
  <div class="details">
23
- <a class="summary" href="#" style="color: #F0F0F0; text-decoration: none; background: #C52F24; border-bottom: none;" onclick="return toggle(<%= wrapper.exception.object_id %>)">
24
- <%= wrapper.exception.class.name %>: <%= h wrapper.exception.message %>
23
+ <a class="summary" href="#" onclick="return toggle(<%= wrapper.exception_id %>)">
24
+ <%= wrapper.exception_class_name %>: <%= h wrapper.message %>
25
25
  </a>
26
26
  </div>
27
27
 
28
- <div id="<%= wrapper.exception.object_id %>" style="display: none;">
28
+ <div id="<%= wrapper.exception_id %>" class="hidden">
29
29
  <%= render "rescues/source", source_extracts: wrapper.source_extracts, show_source_idx: wrapper.source_to_show_id, error_index: index %>
30
30
  <%= render "rescues/trace", traces: wrapper.traces, trace_to_show: wrapper.trace_to_show, error_index: index %>
31
31
  </div>
32
32
  <% end %>
33
33
 
34
34
  <%= render template: "rescues/_request_and_response" %>
35
- </div>
35
+ </main>
@@ -1,9 +1,9 @@
1
- <%= @exception.class.to_s %><%
1
+ <%= @exception_wrapper.exception_class_name %><%
2
2
  if params_valid? && @request.parameters['controller']
3
3
  %> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
4
4
  <% end %>
5
5
 
6
- <%= @exception.message %>
6
+ <%= @exception_wrapper.message %>
7
7
  <%= render template: "rescues/_source" %>
8
8
  <%= render template: "rescues/_trace" %>
9
9
  <%= render template: "rescues/_request_and_response" %>
@@ -1,4 +1,4 @@
1
- <header>
1
+ <header role="banner">
2
2
  <h1>
3
3
  <%= @exception.class.to_s %>
4
4
  <% if @request.parameters['controller'] %>
@@ -7,7 +7,7 @@
7
7
  </h1>
8
8
  </header>
9
9
 
10
- <div id="container">
10
+ <main role="main" id="container">
11
11
  <h2>
12
12
  <%= h @exception.message %>
13
13
  <% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
@@ -21,4 +21,4 @@
21
21
  <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
22
22
  <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %>
23
23
  <%= render template: "rescues/_request_and_response" %>
24
- </div>
24
+ </main>
@@ -3,6 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="turbo-visit-control" content="reload">
6
7
  <title>Action Controller: Exception caught</title>
7
8
  <style>
8
9
  body {
@@ -49,11 +50,19 @@
49
50
  line-height: 25px;
50
51
  }
51
52
 
53
+ code.traces {
54
+ font-size: 11px;
55
+ }
56
+
57
+ .response-heading, .request-heading {
58
+ margin-top: 30px;
59
+ }
60
+
52
61
  .exception-message {
53
62
  padding: 8px 0;
54
63
  }
55
64
 
56
- .exception-message .message{
65
+ .exception-message .message {
57
66
  margin-bottom: 8px;
58
67
  line-height: 25px;
59
68
  font-size: 1.5em;
@@ -75,6 +84,13 @@
75
84
  display: block;
76
85
  }
77
86
 
87
+ a.summary {
88
+ color: #F0F0F0;
89
+ text-decoration: none;
90
+ background: #C52F24;
91
+ border-bottom: none;
92
+ }
93
+
78
94
  .details pre {
79
95
  margin: 5px;
80
96
  border: none;
@@ -114,7 +130,7 @@
114
130
 
115
131
  .source .data .line_numbers {
116
132
  background-color: #ECECEC;
117
- color: #AAA;
133
+ color: #555;
118
134
  padding: 1em .5em;
119
135
  border-right: 1px solid #DDD;
120
136
  text-align: right;
@@ -133,6 +149,18 @@
133
149
  background-color: #FCC;
134
150
  }
135
151
 
152
+ .error_highlight {
153
+ display: inline-block;
154
+ background-color: #FF9;
155
+ text-decoration: #F00 wavy underline;
156
+ }
157
+
158
+ .error_highlight_tip {
159
+ color: #666;
160
+ padding: 2px 2px;
161
+ font-size: 10px;
162
+ }
163
+
136
164
  .button_to {
137
165
  display: inline-block;
138
166
  margin-top: 0.75em;
@@ -143,6 +171,10 @@
143
171
  display: none;
144
172
  }
145
173
 
174
+ .correction {
175
+ list-style-type: none;
176
+ }
177
+
146
178
  input[type="submit"] {
147
179
  color: white;
148
180
  background-color: #C00;
@@ -153,6 +185,7 @@
153
185
  font-weight: bold;
154
186
  margin: 0;
155
187
  padding: 10px 18px;
188
+ cursor: pointer;
156
189
  -webkit-appearance: none;
157
190
  }
158
191
  input[type="submit"]:focus,
@@ -164,15 +197,14 @@
164
197
  transform: translateY(1px)
165
198
  }
166
199
 
167
-
168
200
  a { color: #980905; }
169
201
  a:visited { color: #666; }
170
202
  a.trace-frames {
171
203
  color: #666;
172
204
  overflow-wrap: break-word;
173
205
  }
174
- a:hover { color: #C00; }
175
- a.trace-frames.selected { color: #C00 }
206
+ a:hover, a.trace-frames.selected { color: #C00; }
207
+ a.summary:hover { color: #FFF; }
176
208
 
177
209
  @media (prefers-color-scheme: dark) {
178
210
  body {
@@ -180,11 +212,7 @@
180
212
  color: #ECECEC;
181
213
  }
182
214
 
183
- .details {
184
- border-color: #666;
185
- }
186
-
187
- .summary {
215
+ .details, .summary {
188
216
  border-color: #666;
189
217
  }
190
218
 
@@ -210,6 +238,10 @@
210
238
  background-color: #900;
211
239
  }
212
240
 
241
+ .error_highlight {
242
+ color: #333;
243
+ }
244
+
213
245
  input[type="submit"] {
214
246
  box-shadow: 0 3px #800;
215
247
  }
@@ -219,8 +251,7 @@
219
251
 
220
252
  a { color: #C00; }
221
253
  a.trace-frames { color: #999; }
222
- a:hover { color: #E9382B; }
223
- a.trace-frames.selected { color: #E9382B; }
254
+ a:hover, a.trace-frames.selected { color: #E9382B; }
224
255
  }
225
256
 
226
257
  <%= yield :style %>
@@ -228,8 +259,7 @@
228
259
 
229
260
  <script>
230
261
  var toggle = function(id) {
231
- var s = document.getElementById(id).style;
232
- s.display = s.display == 'none' ? 'block' : 'none';
262
+ document.getElementById(id).classList.toggle('hidden');
233
263
  return false;
234
264
  }
235
265
  var show = function(id) {
@@ -238,9 +268,6 @@
238
268
  var hide = function(id) {
239
269
  document.getElementById(id).style.display = 'none';
240
270
  }
241
- var toggleTrace = function() {
242
- return toggle('blame_trace');
243
- }
244
271
  var toggleSessionDump = function() {
245
272
  return toggle('session_dump');
246
273
  }
@@ -251,7 +278,7 @@
251
278
  </head>
252
279
  <body>
253
280
 
254
- <%= yield %>
281
+ <%= yield %>
255
282
 
256
283
  </body>
257
284
  </html>
@@ -1,19 +1,23 @@
1
- <header>
2
- <h1>No template for interactive request</h1>
1
+ <header role="banner">
2
+ <h1>No view template for interactive request</h1>
3
3
  </header>
4
4
 
5
- <div id="container">
5
+ <main id="container">
6
6
  <h2><%= h @exception.message %></h2>
7
7
 
8
- <p class="summary">
9
- <strong>NOTE!</strong><br>
10
- Unless told otherwise, Rails expects an action to render a template with the same name,<br>
11
- contained in a folder named after its controller.
12
-
13
- If this controller is an API responding with 204 (No Content), <br>
14
- which does not require a template,
15
- then this error will occur when trying to access it via browser,<br>
16
- since we expect an HTML template
17
- to be rendered for such requests. If that's the case, carry on.
18
- </p>
19
- </div>
8
+ <div class="summary">
9
+ <p>
10
+ <strong>NOTE:</strong> Rails usually expects a controller action to render a view template with the same name.
11
+ </p>
12
+ <p>
13
+ For example, a <code><%= @exception.controller %>#<%= @exception.action_name %></code> action defined in <code>app/controllers/<%= @exception.controller.controller_path %>_controller.rb</code> should have a corresponding view template
14
+ in a file named <code>app/views/<%= @exception.controller.controller_name %>/<%= @exception.action_name %>.html.erb</code>.
15
+ </p>
16
+ <p>
17
+ However, if this controller is an API endpoint responding with 204 (No Content), which does not require a view template because it doesn't serve an HTML response, then this error will occur when trying to access it with a browser. In this particular scenario, you can ignore this error.
18
+ </p>
19
+ <p>
20
+ You can find more about view template rendering conventions in the <a href="https://guides.rubyonrails.org/layouts_and_rendering.html#rendering-by-default-convention-over-configuration-in-action">Rails Guides on Layouts and Rendering in Rails</a>.
21
+ </p>
22
+ </div>
23
+ </main>