actionpack 8.0.3 → 8.1.0

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