actionpack 7.1.5.1 → 8.1.2

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.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +308 -523
  3. data/README.rdoc +1 -1
  4. data/lib/abstract_controller/asset_paths.rb +6 -2
  5. data/lib/abstract_controller/base.rb +104 -105
  6. data/lib/abstract_controller/caching/fragments.rb +50 -53
  7. data/lib/abstract_controller/caching.rb +8 -3
  8. data/lib/abstract_controller/callbacks.rb +70 -62
  9. data/lib/abstract_controller/collector.rb +7 -7
  10. data/lib/abstract_controller/deprecator.rb +2 -0
  11. data/lib/abstract_controller/error.rb +2 -0
  12. data/lib/abstract_controller/helpers.rb +71 -84
  13. data/lib/abstract_controller/logger.rb +4 -1
  14. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  15. data/lib/abstract_controller/rendering.rb +13 -13
  16. data/lib/abstract_controller/translation.rb +12 -13
  17. data/lib/abstract_controller/url_for.rb +8 -6
  18. data/lib/abstract_controller.rb +2 -0
  19. data/lib/action_controller/api/api_rendering.rb +2 -0
  20. data/lib/action_controller/api.rb +76 -72
  21. data/lib/action_controller/base.rb +199 -126
  22. data/lib/action_controller/caching.rb +16 -14
  23. data/lib/action_controller/deprecator.rb +2 -0
  24. data/lib/action_controller/form_builder.rb +21 -18
  25. data/lib/action_controller/log_subscriber.rb +23 -2
  26. data/lib/action_controller/metal/allow_browser.rb +133 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  28. data/lib/action_controller/metal/conditional_get.rb +217 -175
  29. data/lib/action_controller/metal/content_security_policy.rb +25 -24
  30. data/lib/action_controller/metal/cookies.rb +4 -2
  31. data/lib/action_controller/metal/data_streaming.rb +72 -63
  32. data/lib/action_controller/metal/default_headers.rb +5 -3
  33. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  34. data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
  35. data/lib/action_controller/metal/exceptions.rb +16 -9
  36. data/lib/action_controller/metal/flash.rb +13 -14
  37. data/lib/action_controller/metal/head.rb +15 -11
  38. data/lib/action_controller/metal/helpers.rb +63 -55
  39. data/lib/action_controller/metal/http_authentication.rb +209 -201
  40. data/lib/action_controller/metal/implicit_render.rb +17 -15
  41. data/lib/action_controller/metal/instrumentation.rb +16 -14
  42. data/lib/action_controller/metal/live.rb +177 -128
  43. data/lib/action_controller/metal/logging.rb +6 -4
  44. data/lib/action_controller/metal/mime_responds.rb +151 -142
  45. data/lib/action_controller/metal/parameter_encoding.rb +34 -32
  46. data/lib/action_controller/metal/params_wrapper.rb +57 -59
  47. data/lib/action_controller/metal/permissions_policy.rb +22 -12
  48. data/lib/action_controller/metal/rate_limiting.rb +92 -0
  49. data/lib/action_controller/metal/redirecting.rb +213 -94
  50. data/lib/action_controller/metal/renderers.rb +78 -57
  51. data/lib/action_controller/metal/rendering.rb +111 -77
  52. data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
  53. data/lib/action_controller/metal/rescue.rb +20 -9
  54. data/lib/action_controller/metal/streaming.rb +118 -195
  55. data/lib/action_controller/metal/strong_parameters.rb +720 -530
  56. data/lib/action_controller/metal/testing.rb +2 -0
  57. data/lib/action_controller/metal/url_for.rb +17 -15
  58. data/lib/action_controller/metal.rb +86 -60
  59. data/lib/action_controller/railtie.rb +36 -15
  60. data/lib/action_controller/railties/helpers.rb +2 -0
  61. data/lib/action_controller/renderer.rb +41 -36
  62. data/lib/action_controller/structured_event_subscriber.rb +116 -0
  63. data/lib/action_controller/template_assertions.rb +4 -2
  64. data/lib/action_controller/test_case.rb +160 -131
  65. data/lib/action_controller.rb +5 -1
  66. data/lib/action_dispatch/constants.rb +8 -0
  67. data/lib/action_dispatch/deprecator.rb +2 -0
  68. data/lib/action_dispatch/http/cache.rb +163 -35
  69. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +54 -39
  71. data/lib/action_dispatch/http/filter_parameters.rb +14 -8
  72. data/lib/action_dispatch/http/filter_redirect.rb +22 -1
  73. data/lib/action_dispatch/http/headers.rb +22 -22
  74. data/lib/action_dispatch/http/mime_negotiation.rb +89 -41
  75. data/lib/action_dispatch/http/mime_type.rb +25 -21
  76. data/lib/action_dispatch/http/mime_types.rb +3 -0
  77. data/lib/action_dispatch/http/param_builder.rb +187 -0
  78. data/lib/action_dispatch/http/param_error.rb +26 -0
  79. data/lib/action_dispatch/http/parameters.rb +14 -12
  80. data/lib/action_dispatch/http/permissions_policy.rb +25 -36
  81. data/lib/action_dispatch/http/query_parser.rb +55 -0
  82. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  83. data/lib/action_dispatch/http/request.rb +141 -92
  84. data/lib/action_dispatch/http/response.rb +137 -77
  85. data/lib/action_dispatch/http/upload.rb +18 -16
  86. data/lib/action_dispatch/http/url.rb +187 -89
  87. data/lib/action_dispatch/journey/formatter.rb +21 -9
  88. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  89. data/lib/action_dispatch/journey/gtg/simulator.rb +34 -11
  90. data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
  91. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  92. data/lib/action_dispatch/journey/nodes/node.rb +8 -6
  93. data/lib/action_dispatch/journey/parser.rb +99 -195
  94. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  95. data/lib/action_dispatch/journey/route.rb +54 -38
  96. data/lib/action_dispatch/journey/router/utils.rb +22 -27
  97. data/lib/action_dispatch/journey/router.rb +63 -83
  98. data/lib/action_dispatch/journey/routes.rb +11 -2
  99. data/lib/action_dispatch/journey/scanner.rb +46 -42
  100. data/lib/action_dispatch/journey/visitors.rb +57 -23
  101. data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
  102. data/lib/action_dispatch/journey.rb +2 -0
  103. data/lib/action_dispatch/log_subscriber.rb +7 -1
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
  106. data/lib/action_dispatch/middleware/callbacks.rb +3 -1
  107. data/lib/action_dispatch/middleware/cookies.rb +125 -106
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
  109. data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
  110. data/lib/action_dispatch/middleware/debug_view.rb +13 -5
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
  112. data/lib/action_dispatch/middleware/executor.rb +19 -4
  113. data/lib/action_dispatch/middleware/flash.rb +63 -51
  114. data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +14 -12
  116. data/lib/action_dispatch/middleware/reloader.rb +5 -3
  117. data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
  118. data/lib/action_dispatch/middleware/request_id.rb +16 -10
  119. data/lib/action_dispatch/middleware/server_timing.rb +4 -2
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +30 -8
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
  125. data/lib/action_dispatch/middleware/ssl.rb +53 -40
  126. data/lib/action_dispatch/middleware/stack.rb +11 -10
  127. data/lib/action_dispatch/middleware/static.rb +33 -31
  128. data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
  130. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
  131. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
  140. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
  141. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
  142. data/lib/action_dispatch/railtie.rb +23 -3
  143. data/lib/action_dispatch/request/session.rb +24 -21
  144. data/lib/action_dispatch/request/utils.rb +11 -3
  145. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  146. data/lib/action_dispatch/routing/inspector.rb +85 -60
  147. data/lib/action_dispatch/routing/mapper.rb +1031 -851
  148. data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
  149. data/lib/action_dispatch/routing/redirection.rb +47 -39
  150. data/lib/action_dispatch/routing/route_set.rb +79 -56
  151. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  152. data/lib/action_dispatch/routing/url_for.rb +130 -125
  153. data/lib/action_dispatch/routing.rb +150 -148
  154. data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
  155. data/lib/action_dispatch/system_test_case.rb +91 -81
  156. data/lib/action_dispatch/system_testing/browser.rb +16 -23
  157. data/lib/action_dispatch/system_testing/driver.rb +2 -0
  158. data/lib/action_dispatch/system_testing/server.rb +2 -0
  159. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
  160. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  161. data/lib/action_dispatch/testing/assertion_response.rb +9 -7
  162. data/lib/action_dispatch/testing/assertions/response.rb +52 -25
  163. data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
  164. data/lib/action_dispatch/testing/assertions.rb +2 -0
  165. data/lib/action_dispatch/testing/integration.rb +233 -223
  166. data/lib/action_dispatch/testing/request_encoder.rb +11 -9
  167. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  168. data/lib/action_dispatch/testing/test_process.rb +11 -8
  169. data/lib/action_dispatch/testing/test_request.rb +3 -1
  170. data/lib/action_dispatch/testing/test_response.rb +27 -26
  171. data/lib/action_dispatch.rb +36 -32
  172. data/lib/action_pack/gem_version.rb +6 -4
  173. data/lib/action_pack/version.rb +3 -1
  174. data/lib/action_pack.rb +17 -16
  175. metadata +36 -32
  176. data/lib/action_dispatch/journey/parser.y +0 -50
  177. data/lib/action_dispatch/journey/parser_extras.rb +0 -31
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionController
4
6
  module Testing
5
7
  # Behavior specific to functional tests
@@ -1,27 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionController
4
- # = Action Controller \UrlFor
6
+ # # Action Controller UrlFor
5
7
  #
6
- # Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
7
- # the <tt>_routes</tt> method. Otherwise, an exception will be raised.
8
+ # Includes `url_for` into the host class. The class has to provide a `RouteSet`
9
+ # by implementing the `_routes` method. Otherwise, an exception will be raised.
8
10
  #
9
- # In addition to AbstractController::UrlFor, this module accesses the HTTP layer to define
10
- # URL options like the +host+. In order to do so, this module requires the host class
11
- # to implement +env+ which needs to be Rack-compatible, and +request+ which
12
- # returns an ActionDispatch::Request instance.
11
+ # In addition to AbstractController::UrlFor, this module accesses the HTTP layer
12
+ # to define URL options like the `host`. In order to do so, this module requires
13
+ # the host class to implement `env` which needs to be Rack-compatible, and
14
+ # `request` which returns an ActionDispatch::Request instance.
13
15
  #
14
- # class RootUrl
15
- # include ActionController::UrlFor
16
- # include Rails.application.routes.url_helpers
16
+ # class RootUrl
17
+ # include ActionController::UrlFor
18
+ # include Rails.application.routes.url_helpers
17
19
  #
18
- # delegate :env, :request, to: :controller
20
+ # delegate :env, :request, to: :controller
19
21
  #
20
- # def initialize(controller)
21
- # @controller = controller
22
- # @url = root_path # named route from the application.
22
+ # def initialize(controller)
23
+ # @controller = controller
24
+ # @url = root_path # named route from the application.
25
+ # end
23
26
  # end
24
- # end
25
27
  module UrlFor
26
28
  extend ActiveSupport::Concern
27
29
 
@@ -1,17 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/array/extract_options"
4
6
  require "action_dispatch/middleware/stack"
5
7
 
6
8
  module ActionController
7
- # = Action Controller \MiddlewareStack
9
+ # # Action Controller MiddlewareStack
8
10
  #
9
- # Extend ActionDispatch middleware stack to make it aware of options
10
- # allowing the following syntax in controllers:
11
+ # Extend ActionDispatch middleware stack to make it aware of options allowing
12
+ # the following syntax in controllers:
11
13
  #
12
- # class PostsController < ApplicationController
13
- # use AuthenticationMiddleware, except: [:index, :show]
14
- # end
14
+ # class PostsController < ApplicationController
15
+ # use AuthenticationMiddleware, except: [:index, :show]
16
+ # end
15
17
  #
16
18
  class MiddlewareStack < ActionDispatch::MiddlewareStack # :nodoc:
17
19
  class Middleware < ActionDispatch::MiddlewareStack::Middleware # :nodoc:
@@ -60,73 +62,71 @@ module ActionController
60
62
  end
61
63
  end
62
64
 
63
- # = Action Controller \Metal
65
+ # # Action Controller Metal
64
66
  #
65
- # +ActionController::Metal+ is the simplest possible controller, providing a
67
+ # `ActionController::Metal` is the simplest possible controller, providing a
66
68
  # valid Rack interface without the additional niceties provided by
67
69
  # ActionController::Base.
68
70
  #
69
71
  # A sample metal controller might look like this:
70
72
  #
71
- # class HelloController < ActionController::Metal
72
- # def index
73
- # self.response_body = "Hello World!"
73
+ # class HelloController < ActionController::Metal
74
+ # def index
75
+ # self.response_body = "Hello World!"
76
+ # end
74
77
  # end
75
- # end
76
78
  #
77
- # And then to route requests to your metal controller, you would add
78
- # something like this to <tt>config/routes.rb</tt>:
79
+ # And then to route requests to your metal controller, you would add something
80
+ # like this to `config/routes.rb`:
79
81
  #
80
- # get 'hello', to: HelloController.action(:index)
82
+ # get 'hello', to: HelloController.action(:index)
81
83
  #
82
- # The +action+ method returns a valid Rack application for the \Rails
83
- # router to dispatch to.
84
+ # The ::action method returns a valid Rack application for the Rails router to
85
+ # dispatch to.
84
86
  #
85
- # == \Rendering \Helpers
87
+ # ## Rendering Helpers
86
88
  #
87
- # +ActionController::Metal+ by default provides no utilities for rendering
88
- # views, partials, or other responses aside from explicitly calling of
89
- # <tt>response_body=</tt>, <tt>content_type=</tt>, and <tt>status=</tt>. To
90
- # add the render helpers you're used to having in a normal controller, you
91
- # can do the following:
89
+ # By default, `ActionController::Metal` provides no utilities for rendering
90
+ # views, partials, or other responses aside from some low-level setters such
91
+ # as #response_body=, #content_type=, and #status=. To add the render helpers
92
+ # you're used to having in a normal controller, you can do the following:
92
93
  #
93
- # class HelloController < ActionController::Metal
94
- # include AbstractController::Rendering
95
- # include ActionView::Layouts
96
- # append_view_path "#{Rails.root}/app/views"
94
+ # class HelloController < ActionController::Metal
95
+ # include AbstractController::Rendering
96
+ # include ActionView::Layouts
97
+ # append_view_path "#{Rails.root}/app/views"
97
98
  #
98
- # def index
99
- # render "hello/index"
99
+ # def index
100
+ # render "hello/index"
101
+ # end
100
102
  # end
101
- # end
102
103
  #
103
- # == Redirection \Helpers
104
+ # ## Redirection Helpers
104
105
  #
105
106
  # To add redirection helpers to your metal controller, do the following:
106
107
  #
107
- # class HelloController < ActionController::Metal
108
- # include ActionController::Redirecting
109
- # include Rails.application.routes.url_helpers
108
+ # class HelloController < ActionController::Metal
109
+ # include ActionController::Redirecting
110
+ # include Rails.application.routes.url_helpers
110
111
  #
111
- # def index
112
- # redirect_to root_url
112
+ # def index
113
+ # redirect_to root_url
114
+ # end
113
115
  # end
114
- # end
115
116
  #
116
- # == Other \Helpers
117
- #
118
- # You can refer to the modules included in ActionController::Base to see
119
- # other features you can bring into your metal controller.
117
+ # ## Other Helpers
120
118
  #
119
+ # You can refer to the modules included in ActionController::Base to see other
120
+ # features you can bring into your metal controller.
121
121
  class Metal < AbstractController::Base
122
122
  abstract!
123
123
 
124
- # Returns the last part of the controller's name, underscored, without the ending
125
- # <tt>Controller</tt>. For instance, +PostsController+ returns <tt>posts</tt>.
126
- # Namespaces are left out, so +Admin::PostsController+ returns <tt>posts</tt> as well.
124
+ # Returns the last part of the controller's name, underscored, without the
125
+ # ending `Controller`. For instance, `PostsController` returns `posts`.
126
+ # Namespaces are left out, so `Admin::PostsController` returns `posts` as well.
127
127
  #
128
- # ==== Returns
129
- # * <tt>string</tt>
128
+ # #### Returns
129
+ # * `string`
130
130
  def self.controller_name
131
131
  @controller_name ||= (name.demodulize.delete_suffix("Controller").underscore unless anonymous?)
132
132
  end
@@ -172,15 +172,40 @@ module ActionController
172
172
  ##
173
173
  # The ActionDispatch::Request::Session instance for the current request.
174
174
  # See further details in the
175
- # {Active Controller Session guide}[https://guides.rubyonrails.org/action_controller_overview.html#session].
175
+ # [Active Controller Session guide](https://guides.rubyonrails.org/action_controller_overview.html#session).
176
176
  delegate :session, to: "@_request"
177
177
 
178
178
  ##
179
179
  # Delegates to ActionDispatch::Response#headers.
180
180
  delegate :headers, to: "@_response"
181
181
 
182
- delegate :status=, :location=, :content_type=,
183
- :status, :location, :content_type, :media_type, to: "@_response"
182
+ ##
183
+ # Delegates to ActionDispatch::Response#status=
184
+ delegate :status=, to: "@_response"
185
+
186
+ ##
187
+ # Delegates to ActionDispatch::Response#location=
188
+ delegate :location=, to: "@_response"
189
+
190
+ ##
191
+ # Delegates to ActionDispatch::Response#content_type=
192
+ delegate :content_type=, to: "@_response"
193
+
194
+ ##
195
+ # Delegates to ActionDispatch::Response#status
196
+ delegate :status, to: "@_response"
197
+
198
+ ##
199
+ # Delegates to ActionDispatch::Response#location
200
+ delegate :location, to: "@_response"
201
+
202
+ ##
203
+ # Delegates to ActionDispatch::Response#content_type
204
+ delegate :content_type, to: "@_response"
205
+
206
+ ##
207
+ # Delegates to ActionDispatch::Response#media_type
208
+ delegate :media_type, to: "@_response"
184
209
 
185
210
  def initialize
186
211
  @_request = nil
@@ -201,7 +226,7 @@ module ActionController
201
226
 
202
227
  alias :response_code :status # :nodoc:
203
228
 
204
- # Basic \url_for that can be overridden for more robust functionality.
229
+ # Basic `url_for` that can be overridden for more robust functionality.
205
230
  def url_for(string)
206
231
  string
207
232
  end
@@ -238,7 +263,8 @@ module ActionController
238
263
  @_response = response
239
264
  end
240
265
 
241
- # Assign the response and mark it as committed. No further processing will occur.
266
+ # Assign the response and mark it as committed. No further processing will
267
+ # occur.
242
268
  def response=(response)
243
269
  set_response!(response)
244
270
 
@@ -271,15 +297,15 @@ module ActionController
271
297
 
272
298
  # The middleware stack used by this controller.
273
299
  #
274
- # By default uses a variation of ActionDispatch::MiddlewareStack which
275
- # allows for the following syntax:
300
+ # By default uses a variation of ActionDispatch::MiddlewareStack which allows
301
+ # for the following syntax:
276
302
  #
277
- # class PostsController < ApplicationController
278
- # use AuthenticationMiddleware, except: [:index, :show]
279
- # end
303
+ # class PostsController < ApplicationController
304
+ # use AuthenticationMiddleware, except: [:index, :show]
305
+ # end
280
306
  #
281
- # Read more about {Rails middleware
282
- # stack}[https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack]
307
+ # Read more about [Rails middleware stack]
308
+ # (https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack)
283
309
  # in the guides.
284
310
  def self.middleware
285
311
  middleware_stack
@@ -300,8 +326,8 @@ module ActionController
300
326
  end
301
327
  end
302
328
 
303
- # Direct dispatch to the controller. Instantiates the controller, then
304
- # executes the action named +name+.
329
+ # Direct dispatch to the controller. Instantiates the controller, then executes
330
+ # the action named `name`.
305
331
  def self.dispatch(name, req, res)
306
332
  if middleware_stack.any?
307
333
  middleware_stack.build(name) { |env| new.dispatch(name, req, res) }.call req.env
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rails"
4
6
  require "action_controller"
5
7
  require "action_dispatch/railtie"
@@ -10,9 +12,11 @@ require "action_view/railtie"
10
12
  module ActionController
11
13
  class Railtie < Rails::Railtie # :nodoc:
12
14
  config.action_controller = ActiveSupport::OrderedOptions.new
13
- config.action_controller.raise_on_open_redirects = false
15
+ config.action_controller.action_on_open_redirect = :log
16
+ config.action_controller.action_on_path_relative_redirect = :log
14
17
  config.action_controller.log_query_tags_around_actions = true
15
18
  config.action_controller.wrap_parameters_by_default = false
19
+ config.action_controller.allowed_redirect_hosts = []
16
20
 
17
21
  config.eager_load_namespaces << AbstractController
18
22
  config.eager_load_namespaces << ActionController
@@ -29,6 +33,10 @@ module ActionController
29
33
  ActionController::Helpers.helpers_path = app.helpers_paths
30
34
  end
31
35
 
36
+ initializer "action_controller.live_streaming_excluded_keys" do |app|
37
+ ActionController::Live.live_streaming_excluded_keys = app.config.action_controller.live_streaming_excluded_keys
38
+ end
39
+
32
40
  initializer "action_controller.parameters_config" do |app|
33
41
  options = app.config.action_controller
34
42
 
@@ -46,11 +54,6 @@ module ActionController
46
54
  end
47
55
 
48
56
  ActionController::Parameters.action_on_unpermitted_parameters = action_on_unpermitted_parameters
49
-
50
- unless options.allow_deprecated_parameters_hash_equality.nil?
51
- ActionController::Parameters.allow_deprecated_parameters_hash_equality =
52
- options.allow_deprecated_parameters_hash_equality
53
- end
54
57
  end
55
58
  end
56
59
 
@@ -58,7 +61,8 @@ module ActionController
58
61
  paths = app.config.paths
59
62
  options = app.config.action_controller
60
63
 
61
- options.logger ||= Rails.logger
64
+ options.logger = options.fetch(:logger, Rails.logger)
65
+
62
66
  options.cache_store ||= Rails.cache
63
67
 
64
68
  options.javascripts_dir ||= paths["public/javascripts"].first
@@ -77,12 +81,13 @@ module ActionController
77
81
 
78
82
  # Configs used in other initializers
79
83
  filtered_options = options.except(
84
+ :default_protect_from_forgery,
80
85
  :log_query_tags_around_actions,
81
86
  :permit_all_parameters,
82
87
  :action_on_unpermitted_parameters,
83
88
  :always_permitted_parameters,
84
89
  :wrap_parameters_by_default,
85
- :allow_deprecated_parameters_hash_equality
90
+ :live_streaming_excluded_keys
86
91
  )
87
92
 
88
93
  filtered_options.each do |k, v|
@@ -96,12 +101,6 @@ module ActionController
96
101
  end
97
102
  end
98
103
 
99
- initializer "action_controller.compile_config_methods" do
100
- ActiveSupport.on_load(:action_controller) do
101
- config.compile_methods! if config.respond_to?(:compile_methods!)
102
- end
103
- end
104
-
105
104
  initializer "action_controller.request_forgery_protection" do |app|
106
105
  ActiveSupport.on_load(:action_controller_base) do
107
106
  if app.config.action_controller.default_protect_from_forgery
@@ -110,6 +109,22 @@ module ActionController
110
109
  end
111
110
  end
112
111
 
112
+ initializer "action_controller.open_redirects" do |app|
113
+ ActiveSupport.on_load(:action_controller, run_once: true) do
114
+ if app.config.action_controller.has_key?(:raise_on_open_redirects)
115
+ ActiveSupport.deprecator.warn(<<~MSG.squish)
116
+ `raise_on_open_redirects` is deprecated and will be removed in a future Rails version.
117
+ Use `config.action_controller.action_on_open_redirect = :raise` instead.
118
+ MSG
119
+
120
+ # Fallback to the default behavior in case of `load_default` set `action_on_open_redirect`, but apps set `raise_on_open_redirects`.
121
+ if app.config.action_controller.raise_on_open_redirects == false && app.config.action_controller.action_on_open_redirect == :raise
122
+ self.action_on_open_redirect = :log
123
+ end
124
+ end
125
+ end
126
+ end
127
+
113
128
  initializer "action_controller.query_log_tags" do |app|
114
129
  query_logs_tags_enabled = app.config.respond_to?(:active_record) &&
115
130
  app.config.active_record.query_log_tags_enabled &&
@@ -120,7 +135,7 @@ module ActionController
120
135
  app.config.active_record.query_log_tags |= [:action]
121
136
 
122
137
  ActiveSupport.on_load(:active_record) do
123
- ActiveRecord::QueryLogs.taggings.merge!(
138
+ ActiveRecord::QueryLogs.taggings = ActiveRecord::QueryLogs.taggings.merge(
124
139
  controller: ->(context) { context[:controller]&.controller_name },
125
140
  action: ->(context) { context[:controller]&.action_name },
126
141
  namespaced_controller: ->(context) {
@@ -142,5 +157,11 @@ module ActionController
142
157
  ActionController::TestCase.executor_around_each_request = app.config.active_support.executor_around_test_case
143
158
  end
144
159
  end
160
+
161
+ initializer "action_controller.backtrace_cleaner" do
162
+ ActiveSupport.on_load(:action_controller) do
163
+ ActionController::LogSubscriber.backtrace_cleaner = Rails.backtrace_cleaner
164
+ end
165
+ end
145
166
  end
146
167
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionController
4
6
  module Railties
5
7
  module Helpers
@@ -1,25 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionController
4
- # = Action Controller \Renderer
6
+ # # Action Controller Renderer
5
7
  #
6
8
  # ActionController::Renderer allows you to render arbitrary templates without
7
9
  # being inside a controller action.
8
10
  #
9
- # You can get a renderer instance by calling +renderer+ on a controller class:
11
+ # You can get a renderer instance by calling `renderer` on a controller class:
10
12
  #
11
- # ApplicationController.renderer
12
- # PostsController.renderer
13
+ # ApplicationController.renderer
14
+ # PostsController.renderer
13
15
  #
14
16
  # and render a template by calling the #render method:
15
17
  #
16
- # ApplicationController.renderer.render template: "posts/show", assigns: { post: Post.first }
17
- # PostsController.renderer.render :show, assigns: { post: Post.first }
18
+ # ApplicationController.renderer.render template: "posts/show", assigns: { post: Post.first }
19
+ # PostsController.renderer.render :show, assigns: { post: Post.first }
18
20
  #
19
- # As a shortcut, you can also call +render+ directly on the controller class itself:
21
+ # As a shortcut, you can also call `render` directly on the controller class
22
+ # itself:
20
23
  #
21
- # ApplicationController.render template: "posts/show", assigns: { post: Post.first }
22
- # PostsController.render :show, assigns: { post: Post.first }
24
+ # ApplicationController.render template: "posts/show", assigns: { post: Post.first }
25
+ # PostsController.render :show, assigns: { post: Post.first }
23
26
  #
24
27
  class Renderer
25
28
  attr_reader :controller
@@ -64,45 +67,46 @@ module ActionController
64
67
 
65
68
  # Creates a new renderer using the same controller, but with a new Rack env.
66
69
  #
67
- # ApplicationController.renderer.new(method: "post")
70
+ # ApplicationController.renderer.new(method: "post")
68
71
  #
69
72
  def new(env = nil)
70
73
  self.class.new controller, env, @defaults
71
74
  end
72
75
 
73
- # Creates a new renderer using the same controller, but with the given
74
- # defaults merged on top of the previous defaults.
76
+ # Creates a new renderer using the same controller, but with the given defaults
77
+ # merged on top of the previous defaults.
75
78
  def with_defaults(defaults)
76
79
  self.class.new controller, @env, @defaults.merge(defaults)
77
80
  end
78
81
 
79
82
  # Initializes a new Renderer.
80
83
  #
81
- # ==== Parameters
84
+ # #### Parameters
85
+ #
86
+ # * `controller` - The controller class to instantiate for rendering.
87
+ # * `env` - The Rack env to use for mocking a request when rendering. Entries
88
+ # can be typical Rack env keys and values, or they can be any of the
89
+ # following, which will be converted appropriately:
90
+ # * `:http_host` - The HTTP host for the incoming request. Converts to
91
+ # Rack's `HTTP_HOST`.
92
+ # * `:https` - Boolean indicating whether the incoming request uses HTTPS.
93
+ # Converts to Rack's `HTTPS`.
94
+ # * `:method` - The HTTP method for the incoming request,
95
+ # case-insensitive. Converts to Rack's `REQUEST_METHOD`.
96
+ # * `:script_name` - The portion of the incoming request's URL path that
97
+ # corresponds to the application. Converts to Rack's `SCRIPT_NAME`.
98
+ # * `:input` - The input stream. Converts to Rack's `rack.input`.
99
+ # * `defaults` - Default values for the Rack env. Entries are specified in the
100
+ # same format as `env`. `env` will be merged on top of these values.
101
+ # `defaults` will be retained when calling #new on a renderer instance.
82
102
  #
83
- # * +controller+ - The controller class to instantiate for rendering.
84
- # * +env+ - The Rack env to use for mocking a request when rendering.
85
- # Entries can be typical Rack env keys and values, or they can be any of
86
- # the following, which will be converted appropriately:
87
- # * +:http_host+ - The HTTP host for the incoming request. Converts to
88
- # Rack's +HTTP_HOST+.
89
- # * +:https+ - Boolean indicating whether the incoming request uses HTTPS.
90
- # Converts to Rack's +HTTPS+.
91
- # * +:method+ - The HTTP method for the incoming request, case-insensitive.
92
- # Converts to Rack's +REQUEST_METHOD+.
93
- # * +:script_name+ - The portion of the incoming request's URL path that
94
- # corresponds to the application. Converts to Rack's +SCRIPT_NAME+.
95
- # * +:input+ - The input stream. Converts to Rack's +rack.input+.
96
- # * +defaults+ - Default values for the Rack env. Entries are specified in
97
- # the same format as +env+. +env+ will be merged on top of these values.
98
- # +defaults+ will be retained when calling #new on a renderer instance.
99
103
  #
100
- # If no +http_host+ is specified, the env HTTP host will be derived from the
101
- # routes' +default_url_options+. In this case, the +https+ boolean and the
102
- # +script_name+ will also be derived from +default_url_options+ if they were
103
- # not specified. Additionally, the +https+ boolean will fall back to
104
- # +Rails.application.config.force_ssl+ if +default_url_options+ does not
105
- # specify a +protocol+.
104
+ # If no `http_host` is specified, the env HTTP host will be derived from the
105
+ # routes' `default_url_options`. In this case, the `https` boolean and the
106
+ # `script_name` will also be derived from `default_url_options` if they were not
107
+ # specified. Additionally, the `https` boolean will fall back to
108
+ # `Rails.application.config.force_ssl` if `default_url_options` does not specify
109
+ # a `protocol`.
106
110
  def initialize(controller, env, defaults)
107
111
  @controller = controller
108
112
  @defaults = defaults
@@ -119,7 +123,8 @@ module ActionController
119
123
  @defaults
120
124
  end
121
125
 
122
- # Renders a template to a string, just like ActionController::Rendering#render_to_string.
126
+ # Renders a template to a string, just like
127
+ # ActionController::Rendering#render_to_string.
123
128
  def render(*args)
124
129
  request = ActionDispatch::Request.new(env_for_request)
125
130
  request.routes = controller._routes
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionController
4
+ class StructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber # :nodoc:
5
+ INTERNAL_PARAMS = %w(controller action format _method only_path)
6
+
7
+ def start_processing(event)
8
+ payload = event.payload
9
+ params = {}
10
+ payload[:params].each_pair do |k, v|
11
+ params[k] = v unless INTERNAL_PARAMS.include?(k)
12
+ end
13
+ format = payload[:format]
14
+ format = format.to_s.upcase if format.is_a?(Symbol)
15
+ format = "*/*" if format.nil?
16
+
17
+ emit_event("action_controller.request_started",
18
+ controller: payload[:controller],
19
+ action: payload[:action],
20
+ format:,
21
+ params:,
22
+ )
23
+ end
24
+
25
+ def process_action(event)
26
+ payload = event.payload
27
+ status = payload[:status]
28
+
29
+ if status.nil? && (exception_class_name = payload[:exception]&.first)
30
+ status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
31
+ end
32
+
33
+ emit_event("action_controller.request_completed", {
34
+ controller: payload[:controller],
35
+ action: payload[:action],
36
+ status: status,
37
+ **additions_for(payload),
38
+ duration_ms: event.duration.round(2),
39
+ gc_time_ms: event.gc_time.round(1),
40
+ }.compact)
41
+ end
42
+
43
+ def halted_callback(event)
44
+ emit_event("action_controller.callback_halted", filter: event.payload[:filter])
45
+ end
46
+
47
+ def rescue_from_callback(event)
48
+ exception = event.payload[:exception]
49
+
50
+ exception_backtrace = exception.backtrace&.first
51
+ exception_backtrace = exception_backtrace&.delete_prefix("#{Rails.root}/") if defined?(Rails.root) && Rails.root
52
+
53
+ emit_event("action_controller.rescue_from_handled",
54
+ exception_class: exception.class.name,
55
+ exception_message: exception.message,
56
+ exception_backtrace:
57
+ )
58
+ end
59
+
60
+ def send_file(event)
61
+ emit_event("action_controller.file_sent", path: event.payload[:path], duration_ms: event.duration.round(1))
62
+ end
63
+
64
+ def redirect_to(event)
65
+ emit_event("action_controller.redirected", location: event.payload[:location])
66
+ end
67
+
68
+ def send_data(event)
69
+ emit_event("action_controller.data_sent", filename: event.payload[:filename], duration_ms: event.duration.round(1))
70
+ end
71
+
72
+ def unpermitted_parameters(event)
73
+ unpermitted_keys = event.payload[:keys]
74
+ context = event.payload[:context]
75
+
76
+ emit_debug_event("action_controller.unpermitted_parameters",
77
+ unpermitted_keys:,
78
+ context: context.except(:request)
79
+ )
80
+ end
81
+ debug_only :unpermitted_parameters
82
+
83
+ def write_fragment(event)
84
+ fragment_cache(__method__, event)
85
+ end
86
+
87
+ def read_fragment(event)
88
+ fragment_cache(__method__, event)
89
+ end
90
+
91
+ def exist_fragment?(event)
92
+ fragment_cache(__method__, event)
93
+ end
94
+
95
+ def expire_fragment(event)
96
+ fragment_cache(__method__, event)
97
+ end
98
+
99
+ private
100
+ def fragment_cache(method_name, event)
101
+ key = ActiveSupport::Cache.expand_cache_key(event.payload[:key] || event.payload[:path])
102
+
103
+ emit_event("action_controller.fragment_cache",
104
+ method: "#{method_name}",
105
+ key: key,
106
+ duration_ms: event.duration.round(1)
107
+ )
108
+ end
109
+
110
+ def additions_for(payload)
111
+ payload.slice(:view_runtime, :db_runtime, :queries_count, :cached_queries_count)
112
+ end
113
+ end
114
+ end
115
+
116
+ ActionController::StructuredEventSubscriber.attach_to :action_controller
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionController
4
6
  module TemplateAssertions # :nodoc:
5
7
  def assert_template(options = {}, message = nil)
6
8
  raise NoMethodError,
7
- "assert_template has been extracted to a gem. To continue using it,
8
- add `gem 'rails-controller-testing'` to your Gemfile."
9
+ 'assert_template has been extracted to a gem. To continue using it,
10
+ add `gem "rails-controller-testing"` to your Gemfile.'
9
11
  end
10
12
  end
11
13
  end