actionpack 8.0.3 → 8.1.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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +347 -155
  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/helpers.rb +1 -1
  8. data/lib/abstract_controller/logger.rb +2 -1
  9. data/lib/action_controller/api.rb +1 -0
  10. data/lib/action_controller/base.rb +2 -1
  11. data/lib/action_controller/caching.rb +1 -2
  12. data/lib/action_controller/form_builder.rb +1 -1
  13. data/lib/action_controller/log_subscriber.rb +18 -3
  14. data/lib/action_controller/metal/allow_browser.rb +1 -1
  15. data/lib/action_controller/metal/conditional_get.rb +25 -0
  16. data/lib/action_controller/metal/data_streaming.rb +1 -3
  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/live.rb +9 -18
  21. data/lib/action_controller/metal/permissions_policy.rb +9 -0
  22. data/lib/action_controller/metal/rate_limiting.rb +30 -9
  23. data/lib/action_controller/metal/redirecting.rb +105 -13
  24. data/lib/action_controller/metal/renderers.rb +27 -6
  25. data/lib/action_controller/metal/rendering.rb +7 -1
  26. data/lib/action_controller/metal/request_forgery_protection.rb +18 -10
  27. data/lib/action_controller/metal/rescue.rb +9 -0
  28. data/lib/action_controller/railtie.rb +27 -8
  29. data/lib/action_controller/structured_event_subscriber.rb +112 -0
  30. data/lib/action_dispatch/http/cache.rb +111 -1
  31. data/lib/action_dispatch/http/filter_parameters.rb +5 -3
  32. data/lib/action_dispatch/http/mime_negotiation.rb +55 -1
  33. data/lib/action_dispatch/http/mime_types.rb +1 -0
  34. data/lib/action_dispatch/http/param_builder.rb +28 -27
  35. data/lib/action_dispatch/http/parameters.rb +3 -3
  36. data/lib/action_dispatch/http/permissions_policy.rb +4 -0
  37. data/lib/action_dispatch/http/query_parser.rb +12 -10
  38. data/lib/action_dispatch/http/request.rb +10 -5
  39. data/lib/action_dispatch/http/response.rb +16 -3
  40. data/lib/action_dispatch/http/url.rb +110 -14
  41. data/lib/action_dispatch/journey/gtg/simulator.rb +33 -12
  42. data/lib/action_dispatch/journey/gtg/transition_table.rb +33 -41
  43. data/lib/action_dispatch/journey/nodes/node.rb +2 -1
  44. data/lib/action_dispatch/journey/route.rb +45 -31
  45. data/lib/action_dispatch/journey/router/utils.rb +8 -14
  46. data/lib/action_dispatch/journey/router.rb +59 -81
  47. data/lib/action_dispatch/journey/routes.rb +7 -0
  48. data/lib/action_dispatch/journey/visitors.rb +55 -23
  49. data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
  50. data/lib/action_dispatch/log_subscriber.rb +7 -3
  51. data/lib/action_dispatch/middleware/cookies.rb +4 -2
  52. data/lib/action_dispatch/middleware/debug_exceptions.rb +7 -1
  53. data/lib/action_dispatch/middleware/debug_view.rb +11 -0
  54. data/lib/action_dispatch/middleware/exception_wrapper.rb +11 -5
  55. data/lib/action_dispatch/middleware/executor.rb +12 -2
  56. data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
  57. data/lib/action_dispatch/middleware/remote_ip.rb +9 -4
  58. data/lib/action_dispatch/middleware/session/cache_store.rb +17 -0
  59. data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
  60. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -2
  61. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
  62. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
  63. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
  64. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
  65. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
  66. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
  67. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
  68. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
  69. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
  70. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
  71. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
  72. data/lib/action_dispatch/railtie.rb +15 -2
  73. data/lib/action_dispatch/routing/inspector.rb +79 -56
  74. data/lib/action_dispatch/routing/mapper.rb +324 -172
  75. data/lib/action_dispatch/routing/redirection.rb +10 -7
  76. data/lib/action_dispatch/routing/route_set.rb +2 -4
  77. data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
  78. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +2 -2
  79. data/lib/action_dispatch/testing/assertions/response.rb +14 -0
  80. data/lib/action_dispatch/testing/assertions/routing.rb +11 -3
  81. data/lib/action_dispatch/testing/integration.rb +1 -1
  82. data/lib/action_dispatch/testing/request_encoder.rb +9 -9
  83. data/lib/action_dispatch.rb +8 -0
  84. data/lib/action_pack/gem_version.rb +2 -2
  85. metadata +13 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b131da258151267320d978699cdc9ed60f96060bbeeb5bfa85f8da0ab648497f
4
- data.tar.gz: 2300ba0391c2e63f5e0ab71060bec7ef3e149d32064e5eccfd1a1f46ecad2820
3
+ metadata.gz: c53f4cddcbfff66aa4ff4a9ffaafc317d3b08c72b31cff8197a4091275fa67ea
4
+ data.tar.gz: e76e733e0add77c1edc5f7cbcb919b6b5afa55da290de9f90e0fb42e7c55fe00
5
5
  SHA512:
6
- metadata.gz: 13ee7198d843341f8b97aa564b70385fd26ee5e3bdd2560e56cc20a16591d8502daa4befec55a81bc4783e5451648acf35dd67de6ca62cf0b41f5ae37cec9557
7
- data.tar.gz: 17972b2a557984ad9a96f3947135fe29dd6aae6dfd0a019204be60e0d82056ed390333bad574ae9ec8d762b24574f4aac8103e04d647fca3a75736763ecae9f6
6
+ metadata.gz: a7b50973de12321c35604c52232fe9452257d7f613b3c59068d3a900042f3cfd22e0aa36507f7f31e86a7031060390136a6a36b2c76e10a602c8c4309a893e41
7
+ data.tar.gz: 4b67fa19b19074660c1ceae3ec08470408cf19a59f851da9bf8471ca3bb5bf50add910c7e904e7190e0cfc78bdffebaec04493c55fb4c2f0e3009d46ab83c8b4
data/CHANGELOG.md CHANGED
@@ -1,285 +1,477 @@
1
- ## Rails 8.0.3 (September 22, 2025) ##
1
+ ## Rails 8.1.1 (October 28, 2025) ##
2
2
 
3
- * URL helpers for engines mounted at the application root handle `SCRIPT_NAME` correctly.
4
-
5
- Fixed an issue where `SCRIPT_NAME` is not applied to paths generated for routes in an engine
6
- mounted at "/".
3
+ * Allow methods starting with underscore to be action methods.
7
4
 
8
- *Mike Dalessio*
5
+ Disallowing methods starting with an underscore from being action methods
6
+ was an unintended side effect of the performance optimization in
7
+ 207a254.
9
8
 
10
- * Fix `Rails.application.reload_routes!` from clearing almost all routes.
11
-
12
- When calling `Rails.application.reload_routes!` inside a middleware of
13
- a Rake task, it was possible under certain conditions that all routes would be cleared.
14
- If ran inside a middleware, this would result in getting a 404 on most page you visit.
15
- This issue was only happening in development.
9
+ Fixes #55985.
16
10
 
17
- *Edouard Chin*
18
-
19
- * Address `rack 3.2` deprecations warnings.
20
-
21
- ```
22
- warning: Status code :unprocessable_entity is deprecated and will be removed in a future version of Rack.
23
- Please use :unprocessable_content instead.
24
- ```
11
+ *Rafael Mendonça França*
25
12
 
26
- Rails API will transparently convert one into the other for the foreseeable future.
27
13
 
28
- *Earlopain*, *Jean Boussier*
14
+ ## Rails 8.1.0 (October 22, 2025) ##
29
15
 
30
- * Support hash-source in Content Security Policy.
16
+ * Submit test requests using `as: :html` with `Content-Type: x-www-form-urlencoded`
31
17
 
32
- *madogiwa*
18
+ *Sean Doyle*
33
19
 
34
- * Always return empty body for HEAD requests in `PublicExceptions` and
35
- `DebugExceptions`.
20
+ * Add link-local IP ranges to `ActionDispatch::RemoteIp` default proxies.
36
21
 
37
- This is required by `Rack::Lint` (per RFC9110).
22
+ Link-local addresses (`169.254.0.0/16` for IPv4 and `fe80::/10` for IPv6)
23
+ are now included in the default trusted proxy list, similar to private IP ranges.
38
24
 
39
- *Hartley McGuire*
25
+ *Adam Daniels*
40
26
 
27
+ * `remote_ip` will no longer ignore IPs in X-Forwarded-For headers if they
28
+ are accompanied by port information.
41
29
 
42
- ## Rails 8.0.2.1 (August 13, 2025) ##
30
+ *Duncan Brown*, *Prevenios Marinos*, *Masafumi Koba*, *Adam Daniels*
43
31
 
44
- * No changes.
32
+ * Add `action_dispatch.verbose_redirect_logs` setting that logs where redirects were called from.
45
33
 
46
- ## Rails 8.0.2 (March 12, 2025) ##
34
+ 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.
47
35
 
48
- * Improve `with_routing` test helper to not rebuild the middleware stack.
36
+ Example:
49
37
 
50
- Otherwise some middleware configuration could be lost.
38
+ ```
39
+ Redirected to http://localhost:3000/posts/1
40
+ ↳ app/controllers/posts_controller.rb:32:in `block (2 levels) in create'
41
+ ```
51
42
 
52
- *Édouard Chin*
43
+ *Dennis Paagman*
53
44
 
54
- * Add resource name to the `ArgumentError` that's raised when invalid `:only` or `:except` options are given to `#resource` or `#resources`
45
+ * Add engine route filtering and better formatting in `bin/rails routes`.
55
46
 
56
- This makes it easier to locate the source of the problem, especially for routes drawn by gems.
47
+ Allow engine routes to be filterable in the routing inspector, and
48
+ improve formatting of engine routing output.
57
49
 
58
50
  Before:
59
51
  ```
60
- :only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]
52
+ > bin/rails routes -e engine_only
53
+ No routes were found for this grep pattern.
54
+ For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html.
61
55
  ```
62
56
 
63
57
  After:
64
58
  ```
65
- Route `resources :products` - :only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]
59
+ > bin/rails routes -e engine_only
60
+ Routes for application:
61
+ No routes were found for this grep pattern.
62
+ For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html.
63
+
64
+ Routes for Test::Engine:
65
+ Prefix Verb URI Pattern Controller#Action
66
+ engine GET /engine_only(.:format) a#b
66
67
  ```
67
68
 
68
- *Jeremy Green*
69
+ *Dennis Paagman*, *Gannon McGibbon*
69
70
 
70
- * Fix `url_for` to handle `:path_params` gracefully when it's not a `Hash`.
71
+ * Add structured events for Action Pack and Action Dispatch:
72
+ - `action_dispatch.redirect`
73
+ - `action_controller.request_started`
74
+ - `action_controller.request_completed`
75
+ - `action_controller.callback_halted`
76
+ - `action_controller.rescue_from_handled`
77
+ - `action_controller.file_sent`
78
+ - `action_controller.redirected`
79
+ - `action_controller.data_sent`
80
+ - `action_controller.unpermitted_parameters`
81
+ - `action_controller.fragment_cache`
71
82
 
72
- Prevents various security scanners from causing exceptions.
83
+ *Adrianna Chang*
73
84
 
74
- *Martin Emde*
85
+ * URL helpers for engines mounted at the application root handle `SCRIPT_NAME` correctly.
75
86
 
76
- * Fix `ActionDispatch::Executor` to unwrap exceptions like other error reporting middlewares.
87
+ Fixed an issue where `SCRIPT_NAME` is not applied to paths generated for routes in an engine
88
+ mounted at "/".
77
89
 
78
- *Jean Boussier*
90
+ *Mike Dalessio*
79
91
 
92
+ * Update `ActionController::Metal::RateLimiting` to support passing method names to `:by` and `:with`
80
93
 
81
- ## Rails 8.0.1 (December 13, 2024) ##
94
+ ```ruby
95
+ class SignupsController < ApplicationController
96
+ rate_limit to: 10, within: 1.minute, with: :redirect_with_flash
82
97
 
83
- * Add `ActionDispatch::Request::Session#store` method to conform Rack spec.
98
+ private
99
+ def redirect_with_flash
100
+ redirect_to root_url, alert: "Too many requests!"
101
+ end
102
+ end
103
+ ```
84
104
 
85
- *Yaroslav*
105
+ *Sean Doyle*
86
106
 
107
+ * Optimize `ActionDispatch::Http::URL.build_host_url` when protocol is included in host.
87
108
 
88
- ## Rails 8.0.0.1 (December 10, 2024) ##
109
+ When using URL helpers with a host that includes the protocol (e.g., `{ host: "https://example.com" }`),
110
+ skip unnecessary protocol normalization and string duplication since the extracted protocol is already
111
+ in the correct format. This eliminates 2 string allocations per URL generation and provides a ~10%
112
+ performance improvement for this case.
89
113
 
90
- * Add validation to content security policies to disallow spaces and semicolons.
91
- Developers should use multiple arguments, and different directive methods instead.
114
+ *Joshua Young*, *Hartley McGuire*
92
115
 
93
- [CVE-2024-54133]
116
+ * Allow `action_controller.logger` to be disabled by setting it to `nil` or `false` instead of always defaulting to `Rails.logger`.
94
117
 
95
- *Gannon McGibbon*
118
+ *Roberto Miranda*
96
119
 
120
+ * Remove deprecated support to a route to multiple paths.
97
121
 
98
- ## Rails 8.0.0 (November 07, 2024) ##
122
+ *Rafael Mendonça França*
99
123
 
100
- * No changes.
124
+ * Remove deprecated support for using semicolons as a query string separator.
101
125
 
126
+ Before:
102
127
 
103
- ## Rails 8.0.0.rc2 (October 30, 2024) ##
128
+ ```ruby
129
+ ActionDispatch::QueryParser.each_pair("foo=bar;baz=quux").to_a
130
+ # => [["foo", "bar"], ["baz", "quux"]]
131
+ ```
104
132
 
105
- * Fix routes with `::` in the path.
133
+ After:
134
+
135
+ ```ruby
136
+ ActionDispatch::QueryParser.each_pair("foo=bar;baz=quux").to_a
137
+ # => [["foo", "bar;baz=quux"]]
138
+ ```
106
139
 
107
140
  *Rafael Mendonça França*
108
141
 
109
- * Maintain Rack 2 parameter parsing behaviour.
142
+ * Remove deprecated support to skipping over leading brackets in parameter names in the parameter parser.
110
143
 
111
- *Matthew Draper*
144
+ Before:
112
145
 
146
+ ```ruby
147
+ ActionDispatch::ParamBuilder.from_query_string("[foo]=bar") # => { "foo" => "bar" }
148
+ ActionDispatch::ParamBuilder.from_query_string("[foo][bar]=baz") # => { "foo" => { "bar" => "baz" } }
149
+ ```
113
150
 
114
- ## Rails 8.0.0.rc1 (October 19, 2024) ##
151
+ After:
115
152
 
116
- * Remove `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality`.
153
+ ```ruby
154
+ ActionDispatch::ParamBuilder.from_query_string("[foo]=bar") # => { "[foo]" => "bar" }
155
+ ActionDispatch::ParamBuilder.from_query_string("[foo][bar]=baz") # => { "[foo]" => { "bar" => "baz" } }
156
+ ```
117
157
 
118
158
  *Rafael Mendonça França*
119
159
 
120
- * Improve `ActionController::TestCase` to expose a binary encoded `request.body`.
160
+ * Deprecate `Rails.application.config.action_dispatch.ignore_leading_brackets`.
121
161
 
122
- The rack spec clearly states:
162
+ *Rafael Mendonça França*
123
163
 
124
- > The input stream is an IO-like object which contains the raw HTTP POST data.
125
- > When applicable, its external encoding must be “ASCII-8BIT” and it must be opened in binary mode.
164
+ * Raise `ActionController::TooManyRequests` error from `ActionController::RateLimiting`
126
165
 
127
- Until now its encoding was generally UTF-8, which doesn't accurately reflect production
128
- behavior.
166
+ Requests that exceed the rate limit raise an `ActionController::TooManyRequests` error.
167
+ By default, Action Dispatch rescues the error and responds with a `429 Too Many Requests` status.
129
168
 
130
- *Jean Boussier*
169
+ *Sean Doyle*
131
170
 
132
- * Update `ActionController::AllowBrowser` to support passing method names to `:block`
171
+ * Add .md/.markdown as Markdown extensions and add a default `markdown:` renderer:
133
172
 
134
173
  ```ruby
135
- class ApplicationController < ActionController::Base
136
- allow_browser versions: :modern, block: :handle_outdated_browser
174
+ class Page
175
+ def to_markdown
176
+ body
177
+ end
178
+ end
137
179
 
138
- private
139
- def handle_outdated_browser
140
- render file: Rails.root.join("public/custom-error.html"), status: :not_acceptable
180
+ class PagesController < ActionController::Base
181
+ def show
182
+ @page = Page.find(params[:id])
183
+
184
+ respond_to do |format|
185
+ format.html
186
+ format.md { render markdown: @page }
141
187
  end
188
+ end
142
189
  end
143
190
  ```
144
191
 
145
- *Sean Doyle*
192
+ *DHH*
146
193
 
147
- * Raise an `ArgumentError` when invalid `:only` or `:except` options are passed into `#resource` and `#resources`.
194
+ * Add headers to engine routes inspection command
148
195
 
149
- *Joshua Young*
196
+ *Petrik de Heus*
150
197
 
151
- ## Rails 8.0.0.beta1 (September 26, 2024) ##
198
+ * Add "Copy as text" button to error pages
152
199
 
153
- * Fix non-GET requests not updating cookies in `ActionController::TestCase`.
200
+ *Mikkel Malmberg*
154
201
 
155
- *Jon Moss*, *Hartley McGuire*
202
+ * Add `scope:` option to `rate_limit` method.
156
203
 
157
- * Update `ActionController::Live` to use a thread-pool to reuse threads across requests.
204
+ Previously, it was not possible to share a rate limit count between several controllers, since the count was by
205
+ default separate for each controller.
158
206
 
159
- *Adam Renberg Tamm*
207
+ Now, the `scope:` option solves this problem.
160
208
 
161
- * Introduce safer, more explicit params handling method with `params#expect` such that
162
- `params.expect(table: [ :attr ])` replaces `params.require(:table).permit(:attr)`
209
+ ```ruby
210
+ class APIController < ActionController::API
211
+ rate_limit to: 2, within: 2.seconds, scope: "api"
212
+ end
213
+
214
+ class API::PostsController < APIController
215
+ # ...
216
+ end
217
+
218
+ class API::UsersController < APIController
219
+ # ...
220
+ end
221
+ ```
222
+
223
+ *ArthurPV*, *Kamil Hanus*
224
+
225
+ * Add support for `rack.response_finished` callbacks in ActionDispatch::Executor.
226
+
227
+ The executor middleware now supports deferring completion callbacks to later
228
+ in the request lifecycle by utilizing Rack's `rack.response_finished` mechanism,
229
+ when available. This enables applications to define `rack.response_finished` callbacks
230
+ that may rely on state that would be cleaned up by the executor's completion callbacks.
163
231
 
164
- Ensures params are filtered with consideration for the expected
165
- types of values, improving handling of params and avoiding ignorable
166
- errors caused by params tampering.
232
+ *Adrianna Chang*, *Hartley McGuire*
233
+
234
+ * Produce a log when `rescue_from` is invoked.
235
+
236
+ *Steven Webb*, *Jean Boussier*
237
+
238
+ * Allow hosts redirects from `hosts` Rails configuration
167
239
 
168
240
  ```ruby
169
- # If the url is altered to ?person=hacked
170
- # Before
171
- params.require(:person).permit(:name, :age, pets: [:name])
172
- # raises NoMethodError, causing a 500 and potential error reporting
241
+ config.action_controller.allowed_redirect_hosts << "example.com"
242
+ ```
173
243
 
174
- # After
175
- params.expect(person: [ :name, :age, pets: [[:name]] ])
176
- # raises ActionController::ParameterMissing, correctly returning a 400 error
244
+ *Kevin Robatel*
245
+
246
+ * `rate_limit.action_controller` notification has additional payload
247
+
248
+ additional values: count, to, within, by, name, cache_key
249
+
250
+ *Jonathan Rochkind*
251
+
252
+ * Add JSON support to the built-in health controller.
253
+
254
+ The health controller now responds to JSON requests with a structured response
255
+ containing status and timestamp information. This makes it easier for monitoring
256
+ tools and load balancers to consume health check data programmatically.
257
+
258
+ ```ruby
259
+ # /up.json
260
+ {
261
+ "status": "up",
262
+ "timestamp": "2025-09-19T12:00:00Z"
263
+ }
177
264
  ```
178
265
 
179
- You may also notice the new double array `[[:name]]`. In order to
180
- declare when a param is expected to be an array of parameter hashes,
181
- this new double array syntax is used to explicitly declare an array.
182
- `expect` requires you to declare expected arrays in this way, and will
183
- ignore arrays that are passed when, for example, `pet: [:name]` is used.
266
+ *Francesco Loreti*, *Juan Vásquez*
184
267
 
185
- In order to preserve compatibility, `permit` does not adopt the new
186
- double array syntax and is therefore more permissive about unexpected
187
- types. Using `expect` everywhere is recommended.
268
+ * Allow to open source file with a crash from the browser.
188
269
 
189
- We suggest replacing `params.require(:person).permit(:name, :age)`
190
- with the direct replacement `params.expect(person: [:name, :age])`
191
- to prevent external users from manipulating params to trigger 500
192
- errors. A 400 error will be returned instead, using public/400.html
270
+ *Igor Kasyanchuk*
193
271
 
194
- Usage of `params.require(:id)` should likewise be replaced with
195
- `params.expect(:id)` which is designed to ensure that `params[:id]`
196
- is a scalar and not an array or hash, also requiring the param.
272
+ * Always check query string keys for valid encoding just like values are checked.
273
+
274
+ *Casper Smits*
275
+
276
+ * Always return empty body for HEAD requests in `PublicExceptions` and
277
+ `DebugExceptions`.
278
+
279
+ This is required by `Rack::Lint` (per RFC9110).
280
+
281
+ *Hartley McGuire*
282
+
283
+ * Add comprehensive support for HTTP Cache-Control request directives according to RFC 9111.
284
+
285
+ Provides a `request.cache_control_directives` object that gives access to request cache directives:
197
286
 
198
287
  ```ruby
199
- # Before
200
- User.find(params.require(:id)) # allows an array, altering behavior
288
+ # Boolean directives
289
+ request.cache_control_directives.only_if_cached? # => true/false
290
+ request.cache_control_directives.no_cache? # => true/false
291
+ request.cache_control_directives.no_store? # => true/false
292
+ request.cache_control_directives.no_transform? # => true/false
293
+
294
+ # Value directives
295
+ request.cache_control_directives.max_age # => integer or nil
296
+ request.cache_control_directives.max_stale # => integer or nil (or true for valueless max-stale)
297
+ request.cache_control_directives.min_fresh # => integer or nil
298
+ request.cache_control_directives.stale_if_error # => integer or nil
299
+
300
+ # Special helpers for max-stale
301
+ request.cache_control_directives.max_stale? # => true if max-stale present (with or without value)
302
+ request.cache_control_directives.max_stale_unlimited? # => true only for valueless max-stale
303
+ ```
201
304
 
202
- # After
203
- User.find(params.expect(:id)) # expect only returns non-blank permitted scalars (excludes Hash, Array, nil, "", etc)
305
+ Example usage:
306
+
307
+ ```ruby
308
+ def show
309
+ if request.cache_control_directives.only_if_cached?
310
+ @article = Article.find_cached(params[:id])
311
+ return head(:gateway_timeout) if @article.nil?
312
+ else
313
+ @article = Article.find(params[:id])
314
+ end
315
+
316
+ render :show
317
+ end
204
318
  ```
205
319
 
206
- *Martin Emde*
320
+ *egg528*
207
321
 
208
- * System Testing: Disable Chrome's search engine choice by default in system tests.
322
+ * Add assert_in_body/assert_not_in_body as the simplest way to check if a piece of text is in the response body.
209
323
 
210
- *glaszig*
324
+ *DHH*
211
325
 
212
- * Fix `Request#raw_post` raising `NoMethodError` when `rack.input` is `nil`.
326
+ * Include cookie name when calculating maximum allowed size.
213
327
 
214
328
  *Hartley McGuire*
215
329
 
216
- * Remove `racc` dependency by manually writing `ActionDispatch::Journey::Scanner`.
330
+ * Implement `must-understand` directive according to RFC 9111.
217
331
 
218
- *Gannon McGibbon*
332
+ 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.
219
333
 
220
- * Speed up `ActionDispatch::Routing::Mapper::Scope#[]` by merging frame hashes.
334
+ ```ruby
335
+ class ArticlesController < ApplicationController
336
+ def show
337
+ @article = Article.find(params[:id])
338
+
339
+ if @article.special_format?
340
+ must_understand
341
+ render status: 203 # Non-Authoritative Information
342
+ else
343
+ fresh_when @article
344
+ end
345
+ end
346
+ end
347
+ ```
221
348
 
222
- *Gannon McGibbon*
349
+ *heka1024*
223
350
 
224
- * Allow bots to ignore `allow_browser`.
351
+ * The JSON renderer doesn't escape HTML entities or Unicode line separators anymore.
225
352
 
226
- *Matthew Nguyen*
353
+ Using `render json:` will no longer escape `<`, `>`, `&`, `U+2028` and `U+2029` characters that can cause errors
354
+ when the resulting JSON is embedded in JavaScript, or vulnerabilities when the resulting JSON is embedded in HTML.
227
355
 
228
- * Deprecate drawing routes with multiple paths to make routing faster.
229
- You may use `with_options` or a loop to make drawing multiple paths easier.
356
+ Since the renderer is used to return a JSON document as `application/json`, it's typically not necessary to escape
357
+ those characters, and it improves performance.
230
358
 
231
- ```ruby
232
- # Before
233
- get "/users", "/other_path", to: "users#index"
359
+ Escaping will still occur when the `:callback` option is set, since the JSON is used as JavaScript code in this
360
+ situation (JSONP).
234
361
 
235
- # After
236
- get "/users", to: "users#index"
237
- get "/other_path", to: "users#index"
362
+ You can use the `:escape` option or set `config.action_controller.escape_json_responses` to `true` to restore the
363
+ escaping behavior.
364
+
365
+ ```ruby
366
+ class PostsController < ApplicationController
367
+ def index
368
+ render json: Post.last(30), escape: true
369
+ end
370
+ end
238
371
  ```
239
372
 
240
- *Gannon McGibbon*
373
+ *Étienne Barrié*, *Jean Boussier*
241
374
 
242
- * Make `http_cache_forever` use `immutable: true`
375
+ * Load lazy route sets before inserting test routes
243
376
 
244
- *Nate Matykiewicz*
377
+ Without loading lazy route sets early, we miss `after_routes_loaded` callbacks, or risk
378
+ invoking them with the test routes instead of the real ones if another load is triggered by an engine.
245
379
 
246
- * Add `config.action_dispatch.strict_freshness`.
380
+ *Gannon McGibbon*
247
381
 
248
- When set to `true`, the `ETag` header takes precedence over the `Last-Modified` header when both are present,
249
- as specified by RFC 7232, Section 6.
382
+ * Raise `AbstractController::DoubleRenderError` if `head` is called after rendering.
250
383
 
251
- Defaults to `false` to maintain compatibility with previous versions of Rails, but is enabled as part of
252
- Rails 8.0 defaults.
384
+ After this change, invoking `head` will lead to an error if response body is already set:
253
385
 
254
- *heka1024*
386
+ ```ruby
387
+ class PostController < ApplicationController
388
+ def index
389
+ render locals: {}
390
+ head :ok
391
+ end
392
+ end
393
+ ```
394
+
395
+ *Iaroslav Kurbatov*
396
+
397
+ * The Cookie Serializer can now serialize an Active Support SafeBuffer when using message pack.
255
398
 
256
- * Support `immutable` directive in Cache-Control
399
+ Such code would previously produce an error if an application was using messagepack as its cookie serializer.
257
400
 
258
401
  ```ruby
259
- expires_in 1.minute, public: true, immutable: true
260
- # Cache-Control: public, max-age=60, immutable
402
+ class PostController < ApplicationController
403
+ def index
404
+ flash.notice = t(:hello_html) # This would try to serialize a SafeBuffer, which was not possible.
405
+ end
406
+ end
261
407
  ```
262
408
 
263
- *heka1024*
409
+ *Edouard Chin*
264
410
 
265
- * Add `:wasm_unsafe_eval` mapping for `content_security_policy`
411
+ * Fix `Rails.application.reload_routes!` from clearing almost all routes.
266
412
 
267
- ```ruby
268
- # Before
269
- policy.script_src "'wasm-unsafe-eval'"
413
+ When calling `Rails.application.reload_routes!` inside a middleware of
414
+ a Rake task, it was possible under certain conditions that all routes would be cleared.
415
+ If ran inside a middleware, this would result in getting a 404 on most page you visit.
416
+ This issue was only happening in development.
270
417
 
271
- # After
272
- policy.script_src :wasm_unsafe_eval
418
+ *Edouard Chin*
419
+
420
+ * Add resource name to the `ArgumentError` that's raised when invalid `:only` or `:except` options are given to `#resource` or `#resources`
421
+
422
+ This makes it easier to locate the source of the problem, especially for routes drawn by gems.
423
+
424
+ Before:
425
+ ```
426
+ :only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]
273
427
  ```
274
428
 
275
- *Joe Haig*
429
+ After:
430
+ ```
431
+ Route `resources :products` - :only and :except must include only [:index, :create, :new, :show, :update, :destroy, :edit], but also included [:foo, :bar]
432
+ ```
433
+
434
+ *Jeremy Green*
435
+
436
+ * A route pointing to a non-existing controller now returns a 500 instead of a 404.
437
+
438
+ A controller not existing isn't a routing error that should result
439
+ in a 404, but a programming error that should result in a 500 and
440
+ be reported.
441
+
442
+ Until recently, this was hard to untangle because of the support
443
+ for dynamic `:controller` segment in routes, but since this is
444
+ deprecated and will be removed in Rails 8.1, we can now easily
445
+ not consider missing controllers as routing errors.
446
+
447
+ *Jean Boussier*
276
448
 
277
- * Add `display_capture` and `keyboard_map` in `permissions_policy`
449
+ * Add `check_collisions` option to `ActionDispatch::Session::CacheStore`.
278
450
 
279
- *Cyril Blaecke*
451
+ Newly generated session ids use 128 bits of randomness, which is more than
452
+ enough to ensure collisions can't happen, but if you need to harden sessions
453
+ even more, you can enable this option to check in the session store that the id
454
+ is indeed free you can enable that option. This however incurs an extra write
455
+ on session creation.
280
456
 
281
- * Add `connect` route helper.
457
+ *Shia*
458
+
459
+ * In ExceptionWrapper, match backtrace lines with built templates more often,
460
+ allowing improved highlighting of errors within do-end blocks in templates.
461
+ Fix for Ruby 3.4 to match new method labels in backtrace.
462
+
463
+ *Martin Emde*
464
+
465
+ * Allow setting content type with a symbol of the Mime type.
466
+
467
+ ```ruby
468
+ # Before
469
+ response.content_type = "text/html"
470
+
471
+ # After
472
+ response.content_type = :html
473
+ ```
282
474
 
283
- *Samuel Williams*
475
+ *Petrik de Heus*
284
476
 
285
- Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/actionpack/CHANGELOG.md) for previous changes.
477
+ 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