actionpack 7.2.3 → 8.1.3

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +394 -119
  3. data/lib/abstract_controller/asset_paths.rb +4 -2
  4. data/lib/abstract_controller/base.rb +11 -5
  5. data/lib/abstract_controller/caching.rb +6 -3
  6. data/lib/abstract_controller/callbacks.rb +6 -0
  7. data/lib/abstract_controller/logger.rb +2 -1
  8. data/lib/abstract_controller/rendering.rb +0 -1
  9. data/lib/action_controller/api.rb +1 -0
  10. data/lib/action_controller/base.rb +3 -2
  11. data/lib/action_controller/caching.rb +1 -2
  12. data/lib/action_controller/form_builder.rb +4 -4
  13. data/lib/action_controller/log_subscriber.rb +22 -3
  14. data/lib/action_controller/metal/allow_browser.rb +12 -2
  15. data/lib/action_controller/metal/conditional_get.rb +30 -1
  16. data/lib/action_controller/metal/data_streaming.rb +5 -5
  17. data/lib/action_controller/metal/exceptions.rb +5 -0
  18. data/lib/action_controller/metal/flash.rb +1 -4
  19. data/lib/action_controller/metal/head.rb +3 -1
  20. data/lib/action_controller/metal/instrumentation.rb +1 -2
  21. data/lib/action_controller/metal/live.rb +65 -25
  22. data/lib/action_controller/metal/permissions_policy.rb +9 -0
  23. data/lib/action_controller/metal/rate_limiting.rb +39 -9
  24. data/lib/action_controller/metal/redirecting.rb +105 -13
  25. data/lib/action_controller/metal/renderers.rb +29 -9
  26. data/lib/action_controller/metal/rendering.rb +7 -1
  27. data/lib/action_controller/metal/request_forgery_protection.rb +18 -10
  28. data/lib/action_controller/metal/rescue.rb +9 -0
  29. data/lib/action_controller/metal/streaming.rb +5 -84
  30. data/lib/action_controller/metal/strong_parameters.rb +277 -89
  31. data/lib/action_controller/railtie.rb +33 -15
  32. data/lib/action_controller/structured_event_subscriber.rb +116 -0
  33. data/lib/action_controller/test_case.rb +12 -2
  34. data/lib/action_dispatch/http/cache.rb +138 -11
  35. data/lib/action_dispatch/http/content_security_policy.rb +14 -1
  36. data/lib/action_dispatch/http/filter_parameters.rb +5 -3
  37. data/lib/action_dispatch/http/mime_negotiation.rb +55 -1
  38. data/lib/action_dispatch/http/mime_types.rb +1 -0
  39. data/lib/action_dispatch/http/param_builder.rb +187 -0
  40. data/lib/action_dispatch/http/param_error.rb +26 -0
  41. data/lib/action_dispatch/http/parameters.rb +3 -3
  42. data/lib/action_dispatch/http/permissions_policy.rb +6 -0
  43. data/lib/action_dispatch/http/query_parser.rb +55 -0
  44. data/lib/action_dispatch/http/request.rb +70 -21
  45. data/lib/action_dispatch/http/response.rb +50 -16
  46. data/lib/action_dispatch/http/url.rb +110 -14
  47. data/lib/action_dispatch/journey/gtg/simulator.rb +33 -12
  48. data/lib/action_dispatch/journey/gtg/transition_table.rb +33 -41
  49. data/lib/action_dispatch/journey/nodes/node.rb +2 -1
  50. data/lib/action_dispatch/journey/parser.rb +99 -196
  51. data/lib/action_dispatch/journey/route.rb +45 -31
  52. data/lib/action_dispatch/journey/router/utils.rb +8 -14
  53. data/lib/action_dispatch/journey/router.rb +59 -81
  54. data/lib/action_dispatch/journey/routes.rb +7 -0
  55. data/lib/action_dispatch/journey/scanner.rb +44 -42
  56. data/lib/action_dispatch/journey/visitors.rb +55 -23
  57. data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
  58. data/lib/action_dispatch/log_subscriber.rb +7 -3
  59. data/lib/action_dispatch/middleware/cookies.rb +8 -4
  60. data/lib/action_dispatch/middleware/debug_exceptions.rb +24 -5
  61. data/lib/action_dispatch/middleware/debug_view.rb +11 -5
  62. data/lib/action_dispatch/middleware/exception_wrapper.rb +11 -11
  63. data/lib/action_dispatch/middleware/executor.rb +12 -2
  64. data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
  65. data/lib/action_dispatch/middleware/remote_ip.rb +11 -5
  66. data/lib/action_dispatch/middleware/request_id.rb +2 -1
  67. data/lib/action_dispatch/middleware/session/cache_store.rb +17 -0
  68. data/lib/action_dispatch/middleware/ssl.rb +13 -3
  69. data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
  70. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
  71. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
  72. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
  73. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
  74. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
  75. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
  76. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
  77. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
  78. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
  79. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
  80. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
  81. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
  82. data/lib/action_dispatch/railtie.rb +21 -0
  83. data/lib/action_dispatch/request/session.rb +1 -0
  84. data/lib/action_dispatch/request/utils.rb +9 -3
  85. data/lib/action_dispatch/routing/inspector.rb +80 -57
  86. data/lib/action_dispatch/routing/mapper.rb +404 -223
  87. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -2
  88. data/lib/action_dispatch/routing/redirection.rb +10 -7
  89. data/lib/action_dispatch/routing/route_set.rb +21 -12
  90. data/lib/action_dispatch/routing/routes_proxy.rb +1 -0
  91. data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
  92. data/lib/action_dispatch/system_test_case.rb +3 -3
  93. data/lib/action_dispatch/system_testing/browser.rb +12 -21
  94. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +2 -2
  95. data/lib/action_dispatch/testing/assertions/response.rb +26 -2
  96. data/lib/action_dispatch/testing/assertions/routing.rb +27 -15
  97. data/lib/action_dispatch/testing/integration.rb +18 -7
  98. data/lib/action_dispatch.rb +14 -4
  99. data/lib/action_pack/gem_version.rb +2 -2
  100. metadata +18 -48
  101. data/lib/action_dispatch/journey/parser.y +0 -50
  102. data/lib/action_dispatch/journey/parser_extras.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e774a50c3ffb6c9c4f387e2bf3632992f1979e8b050cdd481e0ff41fc289f4d4
4
- data.tar.gz: b433f1b952b2cca2850d40a668bbf4196a72dd1981ede7714348607cb79fadb1
3
+ metadata.gz: 1ba808f5ffd02a8121b8ec0cd96f7bf004fc2f05e4459c31cc8a02189325481c
4
+ data.tar.gz: a0396999d33b94532455bc8d4811cc586b8d25b0396c2ae72bdd622055c4ab34
5
5
  SHA512:
6
- metadata.gz: 7c48de1742782bbad870035834911eb2bac273330d2d34317c2d670f02d762d9998f024491fe37e17b8628f4255844d66fec7522bb47e10668e0a775e160e6c4
7
- data.tar.gz: d72cf3db810cc51bfca8ff37af293e22a4089838ec00fb8cc44dce15d77255937a7221a90b6fdd2dc38f01803abd42757641b5fb665d6c121111bf3e548022f4
6
+ metadata.gz: 2b91c87967cb5c30b48b55b46dbc2542cd8aceca3018d995a4fdebcba33f0ff0cbcdcf3c114d82326e3f2b57478a888c4fa2396169b4800f1c2fed9e27be5031
7
+ data.tar.gz: 70438647135541badfc1ecb2f0c07de0bc8823dc8c7c8b9b2daae8ab502a182a77b53d9bac0000409ef43c7c19e610b9cabe9fa43d306525fe33dc28466c524c
data/CHANGELOG.md CHANGED
@@ -1,239 +1,514 @@
1
- ## Rails 7.2.3 (October 28, 2025) ##
1
+ ## Rails 8.1.3 (March 24, 2026) ##
2
2
 
3
- * Submit test requests using `as: :html` with `Content-Type: x-www-form-urlencoded`
3
+ * No changes.
4
4
 
5
- *Sean Doyle*
6
5
 
7
- * Address `rack 3.2` deprecations warnings.
6
+ ## Rails 8.1.2.1 (March 23, 2026) ##
8
7
 
9
- ```
10
- warning: Status code :unprocessable_entity is deprecated and will be removed in a future version of Rack.
11
- Please use :unprocessable_content instead.
8
+ * No changes.
9
+
10
+
11
+ ## Rails 8.1.2 (January 08, 2026) ##
12
+
13
+ * Add `config.action_controller.live_streaming_excluded_keys` to control execution state sharing in ActionController::Live.
14
+
15
+ When using ActionController::Live, actions are executed in a separate thread that shares
16
+ state from the parent thread. This new configuration allows applications to opt-out specific
17
+ state keys that should not be shared.
18
+
19
+ This is useful when streaming inside a `connected_to` block, where you may want
20
+ the streaming thread to use its own database connection context.
21
+
22
+ ```ruby
23
+ # config/application.rb
24
+ config.action_controller.live_streaming_excluded_keys = [:active_record_connected_to_stack]
12
25
  ```
13
26
 
14
- Rails API will transparently convert one into the other for the forseable future.
27
+ By default, all keys are shared.
15
28
 
16
- *Earlopain*, *Jean Boussier*
29
+ *Eileen M. Uchitelle*
17
30
 
18
- * Always return empty body for HEAD requests in `PublicExceptions` and
19
- `DebugExceptions`.
31
+ * Fix `IpSpoofAttackError` message to include `Forwarded` header content.
20
32
 
21
- This is required by `Rack::Lint` (per RFC9110).
33
+ Without it, the error message may be misleading.
22
34
 
23
- *Hartley McGuire*
35
+ *zzak*
24
36
 
25
- * Fix `url_for` to handle `:path_params` gracefully when it's not a `Hash`.
26
37
 
27
- Prevents various security scanners from causing exceptions.
38
+ ## Rails 8.1.1 (October 28, 2025) ##
28
39
 
29
- *Martin Emde*
40
+ * Allow methods starting with underscore to be action methods.
30
41
 
31
- * Fix `ActionDispatch::Executor` to unwrap exceptions like other error reporting middlewares.
42
+ Disallowing methods starting with an underscore from being action methods
43
+ was an unintended side effect of the performance optimization in
44
+ 207a254.
32
45
 
33
- *Jean Boussier*
46
+ Fixes #55985.
34
47
 
35
- * Fix NoMethodError when a non-string CSRF token is passed through headers.
48
+ *Rafael Mendonça França*
36
49
 
37
- *Ryan Heneise*
38
50
 
39
- * Fix invalid response when rescuing `ActionController::Redirecting::UnsafeRedirectError` in a controller.
51
+ ## Rails 8.1.0 (October 22, 2025) ##
40
52
 
41
- *Alex Ghiculescu*
53
+ * Submit test requests using `as: :html` with `Content-Type: x-www-form-urlencoded`
42
54
 
55
+ *Sean Doyle*
43
56
 
44
- ## Rails 7.2.2.2 (August 13, 2025) ##
57
+ * Add link-local IP ranges to `ActionDispatch::RemoteIp` default proxies.
45
58
 
46
- * No changes.
59
+ Link-local addresses (`169.254.0.0/16` for IPv4 and `fe80::/10` for IPv6)
60
+ are now included in the default trusted proxy list, similar to private IP ranges.
47
61
 
62
+ *Adam Daniels*
48
63
 
49
- ## Rails 7.2.2.1 (December 10, 2024) ##
64
+ * `remote_ip` will no longer ignore IPs in X-Forwarded-For headers if they
65
+ are accompanied by port information.
50
66
 
51
- * Add validation to content security policies to disallow spaces and semicolons.
52
- Developers should use multiple arguments, and different directive methods instead.
67
+ *Duncan Brown*, *Prevenios Marinos*, *Masafumi Koba*, *Adam Daniels*
53
68
 
54
- [CVE-2024-54133]
69
+ * Add `action_dispatch.verbose_redirect_logs` setting that logs where redirects were called from.
55
70
 
56
- *Gannon McGibbon*
71
+ Similar to `active_record.verbose_query_logs` and `active_job.verbose_enqueue_logs`, this adds a line in your logs that shows where a redirect was called from.
57
72
 
73
+ Example:
58
74
 
59
- ## Rails 7.2.2 (October 30, 2024) ##
75
+ ```
76
+ Redirected to http://localhost:3000/posts/1
77
+ ↳ app/controllers/posts_controller.rb:32:in `block (2 levels) in create'
78
+ ```
60
79
 
61
- * Fix non-GET requests not updating cookies in `ActionController::TestCase`.
80
+ *Dennis Paagman*
62
81
 
63
- *Jon Moss*, *Hartley McGuire*
82
+ * Add engine route filtering and better formatting in `bin/rails routes`.
64
83
 
84
+ Allow engine routes to be filterable in the routing inspector, and
85
+ improve formatting of engine routing output.
65
86
 
66
- ## Rails 7.2.1.2 (October 23, 2024) ##
87
+ Before:
88
+ ```
89
+ > bin/rails routes -e engine_only
90
+ No routes were found for this grep pattern.
91
+ For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html.
92
+ ```
67
93
 
68
- * No changes.
94
+ After:
95
+ ```
96
+ > bin/rails routes -e engine_only
97
+ Routes for application:
98
+ No routes were found for this grep pattern.
99
+ For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html.
100
+
101
+ Routes for Test::Engine:
102
+ Prefix Verb URI Pattern Controller#Action
103
+ engine GET /engine_only(.:format) a#b
104
+ ```
69
105
 
106
+ *Dennis Paagman*, *Gannon McGibbon*
70
107
 
71
- ## Rails 7.2.1.1 (October 15, 2024) ##
108
+ * Add structured events for Action Pack and Action Dispatch:
109
+ - `action_dispatch.redirect`
110
+ - `action_controller.request_started`
111
+ - `action_controller.request_completed`
112
+ - `action_controller.callback_halted`
113
+ - `action_controller.rescue_from_handled`
114
+ - `action_controller.file_sent`
115
+ - `action_controller.redirected`
116
+ - `action_controller.data_sent`
117
+ - `action_controller.unpermitted_parameters`
118
+ - `action_controller.fragment_cache`
72
119
 
73
- * Avoid regex backtracking in HTTP Token authentication
120
+ *Adrianna Chang*
74
121
 
75
- [CVE-2024-47887]
122
+ * URL helpers for engines mounted at the application root handle `SCRIPT_NAME` correctly.
76
123
 
77
- *John Hawthorn*
124
+ Fixed an issue where `SCRIPT_NAME` is not applied to paths generated for routes in an engine
125
+ mounted at "/".
78
126
 
79
- * Avoid regex backtracking in query parameter filtering
127
+ *Mike Dalessio*
80
128
 
81
- [CVE-2024-41128]
129
+ * Update `ActionController::Metal::RateLimiting` to support passing method names to `:by` and `:with`
82
130
 
83
- *John Hawthorn*
131
+ ```ruby
132
+ class SignupsController < ApplicationController
133
+ rate_limit to: 10, within: 1.minute, with: :redirect_with_flash
84
134
 
135
+ private
136
+ def redirect_with_flash
137
+ redirect_to root_url, alert: "Too many requests!"
138
+ end
139
+ end
140
+ ```
85
141
 
86
- ## Rails 7.2.1 (August 22, 2024) ##
142
+ *Sean Doyle*
87
143
 
88
- * Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
144
+ * Optimize `ActionDispatch::Http::URL.build_host_url` when protocol is included in host.
89
145
 
90
- *Hartley McGuire*
146
+ When using URL helpers with a host that includes the protocol (e.g., `{ host: "https://example.com" }`),
147
+ skip unnecessary protocol normalization and string duplication since the extracted protocol is already
148
+ in the correct format. This eliminates 2 string allocations per URL generation and provides a ~10%
149
+ performance improvement for this case.
91
150
 
151
+ *Joshua Young*, *Hartley McGuire*
92
152
 
93
- ## Rails 7.2.0 (August 09, 2024) ##
153
+ * Allow `action_controller.logger` to be disabled by setting it to `nil` or `false` instead of always defaulting to `Rails.logger`.
94
154
 
95
- * Allow bots to ignore `allow_browser`.
155
+ *Roberto Miranda*
96
156
 
97
- *Matthew Nguyen*
157
+ * Remove deprecated support to a route to multiple paths.
98
158
 
99
- * Include the HTTP Permissions-Policy on non-HTML Content-Types
100
- [CVE-2024-28103]
159
+ *Rafael Mendonça França*
101
160
 
102
- *Aaron Patterson*, *Zack Deveau*
161
+ * Remove deprecated support for using semicolons as a query string separator.
103
162
 
104
- * Fix `Mime::Type.parse` handling type parameters for HTTP Accept headers.
163
+ Before:
105
164
 
106
- *Taylor Chaparro*
165
+ ```ruby
166
+ ActionDispatch::QueryParser.each_pair("foo=bar;baz=quux").to_a
167
+ # => [["foo", "bar"], ["baz", "quux"]]
168
+ ```
107
169
 
108
- * Fix the error page that is displayed when a view template is missing to account for nested controller paths in the
109
- suggested correct location for the missing template.
170
+ After:
110
171
 
111
- *Joshua Young*
172
+ ```ruby
173
+ ActionDispatch::QueryParser.each_pair("foo=bar;baz=quux").to_a
174
+ # => [["foo", "bar;baz=quux"]]
175
+ ```
176
+
177
+ *Rafael Mendonça França*
178
+
179
+ * Remove deprecated support to skipping over leading brackets in parameter names in the parameter parser.
112
180
 
113
- * Add `save_and_open_page` helper to `IntegrationTest`.
181
+ Before:
114
182
 
115
- `save_and_open_page` is a helpful helper to keep a short feedback loop when working on system tests.
116
- A similar helper with matching signature has been added to integration tests.
183
+ ```ruby
184
+ ActionDispatch::ParamBuilder.from_query_string("[foo]=bar") # => { "foo" => "bar" }
185
+ ActionDispatch::ParamBuilder.from_query_string("[foo][bar]=baz") # => { "foo" => { "bar" => "baz" } }
186
+ ```
187
+
188
+ After:
117
189
 
118
- *Joé Dupuis*
190
+ ```ruby
191
+ ActionDispatch::ParamBuilder.from_query_string("[foo]=bar") # => { "[foo]" => "bar" }
192
+ ActionDispatch::ParamBuilder.from_query_string("[foo][bar]=baz") # => { "[foo]" => { "bar" => "baz" } }
193
+ ```
194
+
195
+ *Rafael Mendonça França*
196
+
197
+ * Deprecate `Rails.application.config.action_dispatch.ignore_leading_brackets`.
198
+
199
+ *Rafael Mendonça França*
200
+
201
+ * Raise `ActionController::TooManyRequests` error from `ActionController::RateLimiting`
202
+
203
+ Requests that exceed the rate limit raise an `ActionController::TooManyRequests` error.
204
+ By default, Action Dispatch rescues the error and responds with a `429 Too Many Requests` status.
205
+
206
+ *Sean Doyle*
119
207
 
120
- * Fix a regression in 7.1.3 passing a `to:` option without a controller when the controller is already defined by a scope.
208
+ * Add .md/.markdown as Markdown extensions and add a default `markdown:` renderer:
121
209
 
122
210
  ```ruby
123
- Rails.application.routes.draw do
124
- controller :home do
125
- get "recent", to: "recent_posts"
211
+ class Page
212
+ def to_markdown
213
+ body
214
+ end
215
+ end
216
+
217
+ class PagesController < ActionController::Base
218
+ def show
219
+ @page = Page.find(params[:id])
220
+
221
+ respond_to do |format|
222
+ format.html
223
+ format.md { render markdown: @page }
224
+ end
126
225
  end
127
226
  end
128
227
  ```
129
228
 
130
- *Étienne Barrié*
229
+ *DHH*
230
+
231
+ * Add headers to engine routes inspection command
131
232
 
132
- * Request Forgery takes relative paths into account.
233
+ *Petrik de Heus*
133
234
 
134
- *Stefan Wienert*
235
+ * Add "Copy as text" button to error pages
135
236
 
136
- * Add ".test" as a default allowed host in development to ensure smooth golden-path setup with puma.dev.
237
+ *Mikkel Malmberg*
137
238
 
138
- *DHH*
239
+ * Add `scope:` option to `rate_limit` method.
139
240
 
140
- * Add `allow_browser` to set minimum browser versions for the application.
241
+ Previously, it was not possible to share a rate limit count between several controllers, since the count was by
242
+ default separate for each controller.
141
243
 
142
- A browser that's blocked will by default be served the file in `public/406-unsupported-browser.html` with a HTTP status code of "406 Not Acceptable".
244
+ Now, the `scope:` option solves this problem.
143
245
 
144
246
  ```ruby
145
- class ApplicationController < ActionController::Base
146
- # Allow only browsers natively supporting webp images, web push, badges, import maps, CSS nesting + :has
147
- allow_browser versions: :modern
247
+ class APIController < ActionController::API
248
+ rate_limit to: 2, within: 2.seconds, scope: "api"
148
249
  end
149
250
 
150
- class ApplicationController < ActionController::Base
151
- # All versions of Chrome and Opera will be allowed, but no versions of "internet explorer" (ie). Safari needs to be 16.4+ and Firefox 121+.
152
- allow_browser versions: { safari: 16.4, firefox: 121, ie: false }
251
+ class API::PostsController < APIController
252
+ # ...
153
253
  end
154
254
 
155
- class MessagesController < ApplicationController
156
- # In addition to the browsers blocked by ApplicationController, also block Opera below 104 and Chrome below 119 for the show action.
157
- allow_browser versions: { opera: 104, chrome: 119 }, only: :show
255
+ class API::UsersController < APIController
256
+ # ...
158
257
  end
159
258
  ```
160
259
 
161
- *DHH*
260
+ *ArthurPV*, *Kamil Hanus*
261
+
262
+ * Add support for `rack.response_finished` callbacks in ActionDispatch::Executor.
263
+
264
+ The executor middleware now supports deferring completion callbacks to later
265
+ in the request lifecycle by utilizing Rack's `rack.response_finished` mechanism,
266
+ when available. This enables applications to define `rack.response_finished` callbacks
267
+ that may rely on state that would be cleaned up by the executor's completion callbacks.
268
+
269
+ *Adrianna Chang*, *Hartley McGuire*
270
+
271
+ * Produce a log when `rescue_from` is invoked.
272
+
273
+ *Steven Webb*, *Jean Boussier*
274
+
275
+ * Allow hosts redirects from `hosts` Rails configuration
276
+
277
+ ```ruby
278
+ config.action_controller.allowed_redirect_hosts << "example.com"
279
+ ```
280
+
281
+ *Kevin Robatel*
282
+
283
+ * `rate_limit.action_controller` notification has additional payload
162
284
 
163
- * Add rate limiting API.
285
+ additional values: count, to, within, by, name, cache_key
286
+
287
+ *Jonathan Rochkind*
288
+
289
+ * Add JSON support to the built-in health controller.
290
+
291
+ The health controller now responds to JSON requests with a structured response
292
+ containing status and timestamp information. This makes it easier for monitoring
293
+ tools and load balancers to consume health check data programmatically.
294
+
295
+ ```ruby
296
+ # /up.json
297
+ {
298
+ "status": "up",
299
+ "timestamp": "2025-09-19T12:00:00Z"
300
+ }
301
+ ```
302
+
303
+ *Francesco Loreti*, *Juan Vásquez*
304
+
305
+ * Allow to open source file with a crash from the browser.
306
+
307
+ *Igor Kasyanchuk*
308
+
309
+ * Always check query string keys for valid encoding just like values are checked.
310
+
311
+ *Casper Smits*
312
+
313
+ * Always return empty body for HEAD requests in `PublicExceptions` and
314
+ `DebugExceptions`.
315
+
316
+ This is required by `Rack::Lint` (per RFC9110).
317
+
318
+ *Hartley McGuire*
319
+
320
+ * Add comprehensive support for HTTP Cache-Control request directives according to RFC 9111.
321
+
322
+ Provides a `request.cache_control_directives` object that gives access to request cache directives:
164
323
 
165
324
  ```ruby
166
- class SessionsController < ApplicationController
167
- rate_limit to: 10, within: 3.minutes, only: :create
325
+ # Boolean directives
326
+ request.cache_control_directives.only_if_cached? # => true/false
327
+ request.cache_control_directives.no_cache? # => true/false
328
+ request.cache_control_directives.no_store? # => true/false
329
+ request.cache_control_directives.no_transform? # => true/false
330
+
331
+ # Value directives
332
+ request.cache_control_directives.max_age # => integer or nil
333
+ request.cache_control_directives.max_stale # => integer or nil (or true for valueless max-stale)
334
+ request.cache_control_directives.min_fresh # => integer or nil
335
+ request.cache_control_directives.stale_if_error # => integer or nil
336
+
337
+ # Special helpers for max-stale
338
+ request.cache_control_directives.max_stale? # => true if max-stale present (with or without value)
339
+ request.cache_control_directives.max_stale_unlimited? # => true only for valueless max-stale
340
+ ```
341
+
342
+ Example usage:
343
+
344
+ ```ruby
345
+ def show
346
+ if request.cache_control_directives.only_if_cached?
347
+ @article = Article.find_cached(params[:id])
348
+ return head(:gateway_timeout) if @article.nil?
349
+ else
350
+ @article = Article.find(params[:id])
351
+ end
352
+
353
+ render :show
168
354
  end
355
+ ```
169
356
 
170
- class SignupsController < ApplicationController
171
- rate_limit to: 1000, within: 10.seconds,
172
- by: -> { request.domain }, with: -> { redirect_to busy_controller_url, alert: "Too many signups!" }, only: :new
357
+ *egg528*
358
+
359
+ * Add assert_in_body/assert_not_in_body as the simplest way to check if a piece of text is in the response body.
360
+
361
+ *DHH*
362
+
363
+ * Include cookie name when calculating maximum allowed size.
364
+
365
+ *Hartley McGuire*
366
+
367
+ * Implement `must-understand` directive according to RFC 9111.
368
+
369
+ The `must-understand` directive indicates that a cache must understand the semantics of the response status code, or discard the response. This directive is enforced to be used only with `no-store` to ensure proper cache behavior.
370
+
371
+ ```ruby
372
+ class ArticlesController < ApplicationController
373
+ def show
374
+ @article = Article.find(params[:id])
375
+
376
+ if @article.special_format?
377
+ must_understand
378
+ render status: 203 # Non-Authoritative Information
379
+ else
380
+ fresh_when @article
381
+ end
382
+ end
173
383
  end
174
384
  ```
175
385
 
176
- *DHH*, *Jean Boussier*
386
+ *heka1024*
177
387
 
178
- * Add `image/svg+xml` to the compressible content types of `ActionDispatch::Static`.
388
+ * The JSON renderer doesn't escape HTML entities or Unicode line separators anymore.
179
389
 
180
- *Georg Ledermann*
390
+ Using `render json:` will no longer escape `<`, `>`, `&`, `U+2028` and `U+2029` characters that can cause errors
391
+ when the resulting JSON is embedded in JavaScript, or vulnerabilities when the resulting JSON is embedded in HTML.
181
392
 
182
- * Add instrumentation for `ActionController::Live#send_stream`.
393
+ Since the renderer is used to return a JSON document as `application/json`, it's typically not necessary to escape
394
+ those characters, and it improves performance.
183
395
 
184
- Allows subscribing to `send_stream` events. The event payload contains the filename, disposition, and type.
396
+ Escaping will still occur when the `:callback` option is set, since the JSON is used as JavaScript code in this
397
+ situation (JSONP).
185
398
 
186
- *Hannah Ramadan*
399
+ You can use the `:escape` option or set `config.action_controller.escape_json_responses` to `true` to restore the
400
+ escaping behavior.
187
401
 
188
- * Add support for `with_routing` test helper in `ActionDispatch::IntegrationTest`.
402
+ ```ruby
403
+ class PostsController < ApplicationController
404
+ def index
405
+ render json: Post.last(30), escape: true
406
+ end
407
+ end
408
+ ```
409
+
410
+ *Étienne Barrié*, *Jean Boussier*
411
+
412
+ * Load lazy route sets before inserting test routes
413
+
414
+ Without loading lazy route sets early, we miss `after_routes_loaded` callbacks, or risk
415
+ invoking them with the test routes instead of the real ones if another load is triggered by an engine.
189
416
 
190
417
  *Gannon McGibbon*
191
418
 
192
- * Remove deprecated support to set `Rails.application.config.action_dispatch.show_exceptions` to `true` and `false`.
419
+ * Raise `AbstractController::DoubleRenderError` if `head` is called after rendering.
193
420
 
194
- *Rafael Mendonça França*
421
+ After this change, invoking `head` will lead to an error if response body is already set:
195
422
 
196
- * Remove deprecated `speaker`, `vibrate`, and `vr` permissions policy directives.
423
+ ```ruby
424
+ class PostController < ApplicationController
425
+ def index
426
+ render locals: {}
427
+ head :ok
428
+ end
429
+ end
430
+ ```
197
431
 
198
- *Rafael Mendonça França*
432
+ *Iaroslav Kurbatov*
199
433
 
200
- * Remove deprecated `Rails.application.config.action_dispatch.return_only_request_media_type_on_content_type`.
434
+ * The Cookie Serializer can now serialize an Active Support SafeBuffer when using message pack.
201
435
 
202
- *Rafael Mendonça França*
436
+ Such code would previously produce an error if an application was using messagepack as its cookie serializer.
203
437
 
204
- * Deprecate `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality`.
438
+ ```ruby
439
+ class PostController < ApplicationController
440
+ def index
441
+ flash.notice = t(:hello_html) # This would try to serialize a SafeBuffer, which was not possible.
442
+ end
443
+ end
444
+ ```
205
445
 
206
- *Rafael Mendonça França*
446
+ *Edouard Chin*
207
447
 
208
- * Remove deprecated comparison between `ActionController::Parameters` and `Hash`.
448
+ * Fix `Rails.application.reload_routes!` from clearing almost all routes.
209
449
 
210
- *Rafael Mendonça França*
450
+ When calling `Rails.application.reload_routes!` inside a middleware of
451
+ a Rake task, it was possible under certain conditions that all routes would be cleared.
452
+ If ran inside a middleware, this would result in getting a 404 on most page you visit.
453
+ This issue was only happening in development.
211
454
 
212
- * Remove deprecated constant `AbstractController::Helpers::MissingHelperError`.
455
+ *Edouard Chin*
213
456
 
214
- *Rafael Mendonça França*
457
+ * Add resource name to the `ArgumentError` that's raised when invalid `:only` or `:except` options are given to `#resource` or `#resources`
458
+
459
+ This makes it easier to locate the source of the problem, especially for routes drawn by gems.
215
460
 
216
- * Fix a race condition that could cause a `Text file busy - chromedriver`
217
- error with parallel system tests.
461
+ Before:
462
+ ```
463
+ :only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]
464
+ ```
218
465
 
219
- *Matt Brictson*
466
+ After:
467
+ ```
468
+ Route `resources :products` - :only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]
469
+ ```
220
470
 
221
- * Add `racc` as a dependency since it will become a bundled gem in Ruby 3.4.0
471
+ *Jeremy Green*
222
472
 
223
- *Hartley McGuire*
224
- * Remove deprecated constant `ActionDispatch::IllegalStateError`.
473
+ * A route pointing to a non-existing controller now returns a 500 instead of a 404.
225
474
 
226
- *Rafael Mendonça França*
475
+ A controller not existing isn't a routing error that should result
476
+ in a 404, but a programming error that should result in a 500 and
477
+ be reported.
227
478
 
228
- * Add parameter filter capability for redirect locations.
479
+ Until recently, this was hard to untangle because of the support
480
+ for dynamic `:controller` segment in routes, but since this is
481
+ deprecated and will be removed in Rails 8.1, we can now easily
482
+ not consider missing controllers as routing errors.
229
483
 
230
- It uses the `config.filter_parameters` to match what needs to be filtered.
231
- The result would be like this:
484
+ *Jean Boussier*
232
485
 
233
- Redirected to http://secret.foo.bar?username=roque&password=[FILTERED]
486
+ * Add `check_collisions` option to `ActionDispatch::Session::CacheStore`.
234
487
 
235
- Fixes #14055.
488
+ Newly generated session ids use 128 bits of randomness, which is more than
489
+ enough to ensure collisions can't happen, but if you need to harden sessions
490
+ even more, you can enable this option to check in the session store that the id
491
+ is indeed free you can enable that option. This however incurs an extra write
492
+ on session creation.
493
+
494
+ *Shia*
495
+
496
+ * In ExceptionWrapper, match backtrace lines with built templates more often,
497
+ allowing improved highlighting of errors within do-end blocks in templates.
498
+ Fix for Ruby 3.4 to match new method labels in backtrace.
499
+
500
+ *Martin Emde*
501
+
502
+ * Allow setting content type with a symbol of the Mime type.
503
+
504
+ ```ruby
505
+ # Before
506
+ response.content_type = "text/html"
507
+
508
+ # After
509
+ response.content_type = :html
510
+ ```
236
511
 
237
- *Roque Pinel*, *Trevor Turk*, *tonytonyjan*
512
+ *Petrik de Heus*
238
513
 
239
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actionpack/CHANGELOG.md) for previous changes.
514
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/actionpack/CHANGELOG.md) for previous changes.
@@ -7,8 +7,10 @@ module AbstractController
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- config_accessor :asset_host, :assets_dir, :javascripts_dir,
11
- :stylesheets_dir, :default_asset_host_protocol, :relative_url_root
10
+ singleton_class.delegate :asset_host, :asset_host=, :assets_dir, :assets_dir=, :javascripts_dir, :javascripts_dir=,
11
+ :stylesheets_dir, :stylesheets_dir=, :default_asset_host_protocol, :default_asset_host_protocol=, :relative_url_root, :relative_url_root=, to: :config
12
+ delegate :asset_host, :asset_host=, :assets_dir, :assets_dir=, :javascripts_dir, :javascripts_dir=,
13
+ :stylesheets_dir, :stylesheets_dir=, :default_asset_host_protocol, :default_asset_host_protocol=, :relative_url_root, :relative_url_root=, to: :config
12
14
  end
13
15
  end
14
16
  end