actionpack 6.1.7.5 → 7.1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

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>