activesupport 7.1.6 → 7.2.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 (114) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +212 -1122
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/array_inquirer.rb +1 -1
  5. data/lib/active_support/backtrace_cleaner.rb +10 -3
  6. data/lib/active_support/broadcast_logger.rb +65 -78
  7. data/lib/active_support/cache/file_store.rb +17 -12
  8. data/lib/active_support/cache/mem_cache_store.rb +29 -89
  9. data/lib/active_support/cache/memory_store.rb +7 -6
  10. data/lib/active_support/cache/null_store.rb +2 -2
  11. data/lib/active_support/cache/redis_cache_store.rb +17 -14
  12. data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
  13. data/lib/active_support/cache/strategy/local_cache.rb +56 -20
  14. data/lib/active_support/cache.rb +63 -71
  15. data/lib/active_support/callbacks.rb +77 -115
  16. data/lib/active_support/core_ext/array/conversions.rb +0 -2
  17. data/lib/active_support/core_ext/benchmark.rb +1 -0
  18. data/lib/active_support/core_ext/class/attribute.rb +2 -1
  19. data/lib/active_support/core_ext/class/subclasses.rb +15 -35
  20. data/lib/active_support/core_ext/date/blank.rb +4 -0
  21. data/lib/active_support/core_ext/date/conversions.rb +0 -2
  22. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  23. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  24. data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
  25. data/lib/active_support/core_ext/digest/uuid.rb +6 -0
  26. data/lib/active_support/core_ext/enumerable.rb +17 -5
  27. data/lib/active_support/core_ext/erb/util.rb +7 -2
  28. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  29. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  30. data/lib/active_support/core_ext/module/delegation.rb +20 -163
  31. data/lib/active_support/core_ext/module/deprecation.rb +1 -4
  32. data/lib/active_support/core_ext/module/introspection.rb +3 -0
  33. data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
  34. data/lib/active_support/core_ext/object/blank.rb +45 -1
  35. data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
  36. data/lib/active_support/core_ext/object/json.rb +1 -1
  37. data/lib/active_support/core_ext/object/try.rb +2 -2
  38. data/lib/active_support/core_ext/object/with.rb +5 -3
  39. data/lib/active_support/core_ext/pathname/blank.rb +4 -0
  40. data/lib/active_support/core_ext/range/overlap.rb +1 -1
  41. data/lib/active_support/core_ext/range/sole.rb +17 -0
  42. data/lib/active_support/core_ext/range.rb +1 -0
  43. data/lib/active_support/core_ext/securerandom.rb +4 -4
  44. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  45. data/lib/active_support/core_ext/string/filters.rb +4 -4
  46. data/lib/active_support/core_ext/string/multibyte.rb +3 -3
  47. data/lib/active_support/core_ext/string/output_safety.rb +0 -7
  48. data/lib/active_support/core_ext/time/calculations.rb +18 -28
  49. data/lib/active_support/core_ext/time/compatibility.rb +24 -0
  50. data/lib/active_support/core_ext/time/conversions.rb +0 -2
  51. data/lib/active_support/core_ext/time/zones.rb +1 -1
  52. data/lib/active_support/core_ext.rb +0 -1
  53. data/lib/active_support/current_attributes.rb +45 -40
  54. data/lib/active_support/delegation.rb +202 -0
  55. data/lib/active_support/dependencies/autoload.rb +0 -12
  56. data/lib/active_support/deprecation/constant_accessor.rb +47 -26
  57. data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
  58. data/lib/active_support/deprecation/reporting.rb +7 -2
  59. data/lib/active_support/deprecation.rb +8 -5
  60. data/lib/active_support/descendants_tracker.rb +9 -87
  61. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  62. data/lib/active_support/duration/iso8601_serializer.rb +1 -2
  63. data/lib/active_support/duration.rb +11 -6
  64. data/lib/active_support/encrypted_file.rb +1 -1
  65. data/lib/active_support/error_reporter.rb +46 -5
  66. data/lib/active_support/evented_file_update_checker.rb +0 -1
  67. data/lib/active_support/execution_wrapper.rb +1 -2
  68. data/lib/active_support/file_update_checker.rb +2 -2
  69. data/lib/active_support/fork_tracker.rb +2 -38
  70. data/lib/active_support/gem_version.rb +2 -2
  71. data/lib/active_support/hash_with_indifferent_access.rb +26 -24
  72. data/lib/active_support/html_safe_translation.rb +3 -0
  73. data/lib/active_support/json/decoding.rb +1 -1
  74. data/lib/active_support/json/encoding.rb +23 -5
  75. data/lib/active_support/lazy_load_hooks.rb +1 -1
  76. data/lib/active_support/log_subscriber.rb +0 -12
  77. data/lib/active_support/logger.rb +15 -2
  78. data/lib/active_support/logger_thread_safe_level.rb +0 -8
  79. data/lib/active_support/message_encryptors.rb +2 -2
  80. data/lib/active_support/message_pack/extensions.rb +15 -2
  81. data/lib/active_support/message_verifier.rb +21 -0
  82. data/lib/active_support/message_verifiers.rb +5 -3
  83. data/lib/active_support/messages/rotator.rb +5 -0
  84. data/lib/active_support/multibyte/chars.rb +6 -3
  85. data/lib/active_support/notifications/fanout.rb +4 -7
  86. data/lib/active_support/notifications/instrumenter.rb +21 -18
  87. data/lib/active_support/notifications.rb +28 -27
  88. data/lib/active_support/number_helper/number_converter.rb +2 -2
  89. data/lib/active_support/option_merger.rb +2 -2
  90. data/lib/active_support/ordered_options.rb +53 -15
  91. data/lib/active_support/proxy_object.rb +8 -5
  92. data/lib/active_support/railtie.rb +4 -11
  93. data/lib/active_support/string_inquirer.rb +1 -1
  94. data/lib/active_support/subscriber.rb +1 -0
  95. data/lib/active_support/tagged_logging.rb +0 -1
  96. data/lib/active_support/test_case.rb +3 -1
  97. data/lib/active_support/testing/assertions.rb +4 -4
  98. data/lib/active_support/testing/constant_stubbing.rb +30 -8
  99. data/lib/active_support/testing/deprecation.rb +5 -12
  100. data/lib/active_support/testing/isolation.rb +20 -8
  101. data/lib/active_support/testing/method_call_assertions.rb +2 -16
  102. data/lib/active_support/testing/parallelization/server.rb +18 -2
  103. data/lib/active_support/testing/parallelization/worker.rb +2 -2
  104. data/lib/active_support/testing/parallelization.rb +12 -1
  105. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  106. data/lib/active_support/testing/time_helpers.rb +3 -3
  107. data/lib/active_support/time_with_zone.rb +8 -4
  108. data/lib/active_support/values/time_zone.rb +7 -7
  109. data/lib/active_support/xml_mini.rb +13 -2
  110. data/lib/active_support.rb +2 -1
  111. metadata +16 -24
  112. data/lib/active_support/deprecation/instance_delegator.rb +0 -65
  113. data/lib/active_support/ruby_features.rb +0 -7
  114. data/lib/active_support/testing/strict_warnings.rb +0 -39
data/CHANGELOG.md CHANGED
@@ -1,1342 +1,432 @@
1
- ## Rails 7.1.6 (October 28, 2025) ##
1
+ ## Rails 7.2.3 (October 28, 2025) ##
2
2
 
3
- * No changes.
4
-
5
-
6
- ## Rails 7.1.5.2 (August 13, 2025) ##
7
-
8
- * No changes.
9
-
10
-
11
- ## Rails 7.1.5.1 (December 10, 2024) ##
12
-
13
- * No changes.
14
-
15
-
16
- ## Rails 7.1.5 (October 30, 2024) ##
17
-
18
- * No changes.
19
-
20
-
21
- ## Rails 7.1.4.2 (October 23, 2024) ##
22
-
23
- * No changes.
24
-
25
-
26
- ## Rails 7.1.4.1 (October 15, 2024) ##
27
-
28
- * No changes.
29
-
30
-
31
- ## Rails 7.1.4 (August 22, 2024) ##
32
-
33
- * Improve compatibility for `ActiveSupport::BroadcastLogger`.
34
-
35
- *Máximo Mussini*
36
-
37
- * Pass options along to write_entry in handle_expired_entry method.
38
-
39
- *Graham Cooper*
40
-
41
- * Fix Active Support configurations deprecations.
42
-
43
- *fatkodima*
44
-
45
- * Fix teardown callbacks.
3
+ * Fix `Enumerable#sole` to return the full tuple instead of just the first element of the tuple.
46
4
 
47
- *Tristan Starck*
5
+ *Olivier Bellone*
48
6
 
49
- * `BacktraceCleaner` silence core internal methods by default.
7
+ * Fix parallel tests hanging when worker processes die abruptly.
50
8
 
51
- *Jean Boussier*
52
-
53
- * Fix `delegate_missing_to allow_nil: true` when called with implict self
54
-
55
- ```ruby
56
- class Person
57
- delegate_missing_to :address, allow_nil: true
58
-
59
- def address
60
- nil
61
- end
62
-
63
- def berliner?
64
- city == "Berlin"
65
- end
66
- end
9
+ Previously, if a worker process was killed (e.g., OOM killed, `kill -9`) during parallel
10
+ test execution, the test suite would hang forever waiting for the dead worker.
67
11
 
68
- Person.new.city # => nil
69
- Person.new.berliner? # undefined local variable or method `city' for an instance of Person (NameError)
70
- ```
12
+ *Joshua Young*
71
13
 
72
- *Jean Boussier*
14
+ * `ActiveSupport::FileUpdateChecker` does not depend on `Time.now` to prevent unnecessary reloads with time travel test helpers
73
15
 
74
- * Work around a Ruby bug that can cause a VM crash.
16
+ *Jan Grodowski*
75
17
 
76
- This would happen if using `TaggerLogger` with a Proc
77
- formatter on which you called `object_id`.
18
+ * Fix `ActiveSupport::BroadcastLogger` from executing a block argument for each logger (tagged, info, etc.).
78
19
 
79
- ```
80
- [BUG] Object ID seen, but not in mapping table: proc
81
- ```
20
+ *Jared Armstrong*
82
21
 
83
- *Jean Boussier*
22
+ * Fix `ActiveSupport::HashWithIndifferentAccess#transform_keys!` removing defaults.
84
23
 
85
- * Fix `ActiveSupport::Notifications.publish_event` to preserve units.
86
-
87
- This solves the incorrect reporting of time spent running Active Record
88
- asynchronous queries (by a factor `1000`).
89
-
90
- *Jean Boussier*
24
+ *Hartley McGuire*
91
25
 
92
- * Revert "Fix `ActiveSupport::JSON.encode` to prevent duplicate keys." introduced in 7.1.3
26
+ * Fix `ActiveSupport::HashWithIndifferentAccess#tranform_keys!` to handle collisions.
93
27
 
94
- If the same key exist in both String and Symbol form, json encoder
95
- again emits the same key twice. [Reaseon](https://github.com/rails/rails/pull/50489#issuecomment-2123881327)
28
+ If the transformation would result in a key equal to another not yet transformed one,
29
+ it would result in keys being lost.
96
30
 
97
- ActiveSupport 7.1.3
98
- ```ruby
99
- {a: 1, "a" => 2}.to_json
100
- # gives: "{\"a\":2}"
101
- ```
31
+ Before:
102
32
 
103
- ActiveSupport 7.1.4
104
33
  ```ruby
105
- {a: 1, "a" => 2}.to_json
106
- # gives: "{\"a\":1,\"a\":2}"
34
+ >> {a: 1, b: 2}.with_indifferent_access.transform_keys!(&:succ)
35
+ => {"c" => 1}
107
36
  ```
108
37
 
109
- *Rafael Mendonça França*
110
-
111
-
112
- ## Rails 7.1.3.4 (June 04, 2024) ##
113
-
114
- * No changes.
115
-
116
-
117
- ## Rails 7.1.3.3 (May 16, 2024) ##
118
-
119
- * No changes.
120
-
121
-
122
- ## Rails 7.1.3.2 (February 21, 2024) ##
123
-
124
- * No changes.
125
-
126
-
127
- ## Rails 7.1.3.1 (February 21, 2024) ##
128
-
129
- * No changes.
130
-
131
-
132
- ## Rails 7.1.3 (January 16, 2024) ##
133
-
134
- * Handle nil `backtrace_locations` in `ActiveSupport::SyntaxErrorProxy`.
135
-
136
- *Eugene Kenny*
137
-
138
- * Fix `ActiveSupport::JSON.encode` to prevent duplicate keys.
139
-
140
- If the same key exist in both String and Symbol form it could
141
- lead to the same key being emitted twice.
142
-
143
- ActiveSupport 7.1.2
144
- ```ruby
145
- {a: 1, "a" => 2}.to_json
146
- # gives: "{\"a\":1,\"a\":2}"
147
- ```
38
+ After:
148
39
 
149
- ActiveSupport 7.1.3
150
40
  ```ruby
151
- {a: 1, "a" => 2}.to_json
152
- # gives: "{\"a\":2}"
41
+ >> {a: 1, b: 2}.with_indifferent_access.transform_keys!(&:succ)
42
+ => {"c" => 1, "d" => 2}
153
43
  ```
154
44
 
155
- *Manish Sharma*
156
-
157
- * Fix `ActiveSupport::Cache::Store#read_multi` when using a cache namespace
158
- and local cache strategy.
159
-
160
- *Mark Oleson*
161
-
162
- * Fix `Time.now/DateTime.now/Date.today` to return results in a system timezone after `#travel_to`.
163
-
164
- There is a bug in the current implementation of #travel_to:
165
- it remembers a timezone of its argument, and all stubbed methods start
166
- returning results in that remembered timezone. However, the expected
167
- behaviour is to return results in a system timezone.
168
-
169
- *Aleksei Chernenkov*
170
-
171
- * Fix `:unless_exist` option for `MemoryStore#write` (et al) when using a
172
- cache namespace.
173
-
174
- *S. Brent Faulkner*
175
-
176
- * Fix ActiveSupport::Deprecation to handle blaming generated code.
177
-
178
- *Jean Boussier*, *fatkodima*
179
-
180
-
181
- ## Rails 7.1.2 (November 10, 2023) ##
182
-
183
- * Fix `:expires_in` option for `RedisCacheStore#write_multi`.
184
-
185
- *fatkodima*
186
-
187
- * Fix deserialization of non-string "purpose" field in Message serializer
188
-
189
- *Jacopo Beschi*
190
-
191
- * Prevent global cache options being overwritten when setting dynamic options
192
- inside a `ActiveSupport::Cache::Store#fetch` block.
193
-
194
- *Yasha Krasnou*
195
-
196
- * Fix missing `require` resulting in `NoMethodError` when running
197
- `bin/rails secrets:show` or `bin/rails secrets:edit`.
198
-
199
- *Stephen Ierodiaconou*
200
-
201
- * Ensure `{down,up}case_first` returns non-frozen string.
202
-
203
- *Jonathan Hefner*
204
-
205
- * Fix `#to_fs(:human_size)` to correctly work with negative numbers.
206
-
207
- *Earlopain*
208
-
209
- * Fix `BroadcastLogger#dup` so that it duplicates the logger's `broadcasts`.
45
+ *Jason T Johnson*, *Jean Boussier*
210
46
 
211
- *Andrew Novoselac*
47
+ * Fix `ActiveSupport::Cache::MemCacheStore#read_multi` to handle network errors.
212
48
 
213
- * Fix issue where `bootstrap.rb` overwrites the `level` of a `BroadcastLogger`'s `broadcasts`.
49
+ This method specifically wasn't handling network errors like other codepaths.
214
50
 
215
- *Andrew Novoselac*
51
+ *Alessandro Dal Grande*
216
52
 
217
- * Fix `ActiveSupport::Cache` to handle outdated Marshal payload from Rails 6.1 format.
53
+ * Fix Active Support Cache `fetch_multi` when local store is active.
218
54
 
219
- Active Support's Cache is supposed to treat a Marshal payload that can no longer be
220
- deserialized as a cache miss. It fail to do so for compressed payload in the Rails 6.1
221
- legacy format.
55
+ `fetch_multi` now properly yield to the provided block for missing entries
56
+ that have been recorded as such in the local store.
222
57
 
223
58
  *Jean Boussier*
224
59
 
225
- * Fix `OrderedOptions#dig` for array indexes.
226
-
227
- *fatkodima*
228
-
229
- * Fix time travel helpers to work when nested using with separate classes.
230
-
231
- *fatkodima*
232
-
233
- * Fix `delete_matched` for file cache store to work with keys longer than the
234
- max filename size.
235
-
236
- *fatkodima* and *Jonathan Hefner*
237
-
238
- * Fix compatibility with the `semantic_logger` gem.
239
-
240
- The `semantic_logger` gem doesn't behave exactly like stdlib logger in that
241
- `SemanticLogger#level` returns a Symbol while stdlib `Logger#level` returns an Integer.
242
-
243
- This caused the various `LogSubscriber` classes in Rails to break when assigned a
244
- `SemanticLogger` instance.
245
-
246
- *Jean Boussier*, *ojab*
247
-
248
- ## Rails 7.1.1 (October 11, 2023) ##
249
-
250
- * Add support for keyword arguments when delegating calls to custom loggers from `ActiveSupport::BroadcastLogger`.
251
-
252
- *Edouard Chin*
253
-
254
- * `NumberHelper`: handle objects responding `to_d`.
255
-
256
- *fatkodima*
257
-
258
- * Fix RedisCacheStore to properly set the TTL when incrementing or decrementing.
259
-
260
- This bug was only impacting Redis server older than 7.0.
261
-
262
- *Thomas Countz*
263
-
264
- * Fix MemoryStore to prevent race conditions when incrementing or decrementing.
265
-
266
- *Pierre Jambet*
267
-
268
-
269
- ## Rails 7.1.0 (October 05, 2023) ##
270
-
271
- * No changes.
272
-
273
-
274
- ## Rails 7.1.0.rc2 (October 01, 2023) ##
60
+ * Fix execution wrapping to report all exceptions, including `Exception`.
275
61
 
276
- * Fix `AS::MessagePack` with `ENV["RAILS_MAX_THREADS"]`.
62
+ If a more serious error like `SystemStackError` or `NoMemoryError` happens,
63
+ the error reporter should be able to report these kinds of exceptions.
277
64
 
278
- *Jonathan Hefner*
279
-
280
-
281
- ## Rails 7.1.0.rc1 (September 27, 2023) ##
282
-
283
- * Add a new public API for broadcasting logs
284
-
285
- This feature existed for a while but was until now a private API.
286
- Broadcasting log allows to send log message to difference sinks (STDOUT, a file ...) and
287
- is used by default in the development environment to write logs both on STDOUT and in the
288
- "development.log" file.
65
+ *Gannon McGibbon*
289
66
 
290
- Basic usage:
67
+ * Fix `RedisCacheStore` and `MemCacheStore` to also handle connection pool related errors.
291
68
 
292
- ```ruby
293
- stdout_logger = Logger.new(STDOUT)
294
- file_logger = Logger.new("development.log")
295
- broadcast = ActiveSupport::BroadcastLogger.new(stdout_logger, file_logger)
69
+ These errors are rescued and reported to `Rails.error`.
296
70
 
297
- broadcast.info("Hello!") # The "Hello!" message is written on STDOUT and in the log file.
298
- ```
71
+ *Jean Boussier*
299
72
 
300
- Adding other sink(s) to the broadcast:
73
+ * Fix `ActiveSupport::Cache#read_multi` to respect version expiry when using local cache.
301
74
 
302
- ```ruby
303
- broadcast = ActiveSupport::BroadcastLogger.new
304
- broadcast.broadcast_to(Logger.new(STDERR))
305
- ```
75
+ *zzak*
306
76
 
307
- Remove a sink from the broadcast:
77
+ * Fix `ActiveSupport::MessageVerifier` and `ActiveSupport::MessageEncryptor` configuration of `on_rotation` callback.
308
78
 
309
79
  ```ruby
310
- stdout_logger = Logger.new(STDOUT)
311
- broadcast = ActiveSupport::BroadcastLogger.new(stdout_logger)
312
-
313
- broadcast.stop_broadcasting_to(stdout_logger)
80
+ verifier.rotate(old_secret).on_rotation { ... }
314
81
  ```
315
82
 
316
- *Edouard Chin*
317
-
318
- * Fix Range#overlap? not taking empty ranges into account on Ruby < 3.3
319
-
320
- *Nobuyoshi Nakada*, *Shouichi Kamiya*, *Hartley McGuire*
321
-
322
- * Use Ruby 3.3 Range#overlap? if available
323
-
324
- *Yasuo Honda*
325
-
326
-
327
- ## Rails 7.1.0.beta1 (September 13, 2023) ##
328
-
329
- * Add `bigdecimal` as Active Support dependency that is a bundled gem candidate for Ruby 3.4.
330
-
331
- `bigdecimal` 3.1.4 or higher version will be installed.
332
- Ruby 2.7 and 3.0 users who want `bigdecimal` version 2.0.0 or 3.0.0 behavior as a default gem,
333
- pin the `bigdecimal` version in your application Gemfile.
334
-
335
- *Koichi ITO*
336
-
337
- * Add `drb`, `mutex_m` and `base64` that are bundled gem candidates for Ruby 3.4
338
-
339
- *Yasuo Honda*
83
+ Now both work as documented.
340
84
 
341
- * When using cache format version >= 7.1 or a custom serializer, expired and
342
- version-mismatched cache entries can now be detected without deserializing
343
- their values.
344
-
345
- *Jonathan Hefner*
346
-
347
- * Make all cache stores return a boolean for `#delete`
348
-
349
- Previously the `RedisCacheStore#delete` would return `1` if the entry
350
- exists and `0` otherwise. Now it returns true if the entry exists and false
351
- otherwise, just like the other stores.
352
-
353
- The `FileStore` would return `nil` if the entry doesn't exists and returns
354
- `false` now as well.
355
-
356
- *Petrik de Heus*
357
-
358
- * Active Support cache stores now support replacing the default compressor via
359
- a `:compressor` option. The specified compressor must respond to `deflate`
360
- and `inflate`. For example:
361
-
362
- ```ruby
363
- module MyCompressor
364
- def self.deflate(string)
365
- # compression logic...
366
- end
367
-
368
- def self.inflate(compressed)
369
- # decompression logic...
370
- end
371
- end
372
-
373
- config.cache_store = :redis_cache_store, { compressor: MyCompressor }
374
- ```
375
-
376
- *Jonathan Hefner*
377
-
378
- * Active Support cache stores now support a `:serializer` option. Similar to
379
- the `:coder` option, serializers must respond to `dump` and `load`. However,
380
- serializers are only responsible for serializing a cached value, whereas
381
- coders are responsible for serializing the entire `ActiveSupport::Cache::Entry`
382
- instance. Additionally, the output from serializers can be automatically
383
- compressed, whereas coders are responsible for their own compression.
384
-
385
- Specifying a serializer instead of a coder also enables performance
386
- optimizations, including the bare string optimization introduced by cache
387
- format version 7.1.
388
-
389
- The `:serializer` and `:coder` options are mutually exclusive. Specifying
390
- both will raise an `ArgumentError`.
391
-
392
- *Jonathan Hefner*
85
+ *Jean Boussier*
393
86
 
394
- * Fix `ActiveSupport::Inflector.humanize(nil)` raising ``NoMethodError: undefined method `end_with?' for nil:NilClass``.
87
+ * Fix `ActiveSupport::MessageVerifier` to always be able to verify both URL-safe and URL-unsafe payloads.
395
88
 
396
- *James Robinson*
89
+ This is to allow transitioning seemlessly from either configuration without immediately invalidating
90
+ all previously generated signed messages.
397
91
 
398
- * Don't show secrets for `ActiveSupport::KeyGenerator#inspect`.
92
+ *Jean Boussier*, *Florent Beaurain*, *Ali Sepehri*
399
93
 
400
- Before:
94
+ * Fix `cache.fetch` to honor the provided expiry when `:race_condition_ttl` is used.
401
95
 
402
96
  ```ruby
403
- ActiveSupport::KeyGenerator.new(secret).inspect
404
- "#<ActiveSupport::KeyGenerator:0x0000000104888038 ... @secret=\"\\xAF\\bFh]LV}q\\nl\\xB2U\\xB3 ... >"
405
- ```
406
-
407
- After:
408
-
409
- ```ruby
410
- ActiveSupport::KeyGenerator::Aes256Gcm(secret).inspect
411
- "#<ActiveSupport::KeyGenerator:0x0000000104888038>"
97
+ cache.fetch("key", expires_in: 1.hour, race_condition_ttl: 5.second) do
98
+ "something"
99
+ end
412
100
  ```
413
101
 
414
- *Petrik de Heus*
102
+ In the above example, the final cache entry would have a 10 seconds TTL instead
103
+ of the requested 1 hour.
415
104
 
416
- * Improve error message when EventedFileUpdateChecker is used without a
417
- compatible version of the Listen gem
418
-
419
- *Hartley McGuire*
105
+ *Dhia*
420
106
 
421
- * Add `:report` behavior for Deprecation
107
+ * Better handle procs with splat arguments in `set_callback`.
422
108
 
423
- Setting `config.active_support.deprecation = :report` uses the error
424
- reporter to report deprecation warnings to `ActiveSupport::ErrorReporter`.
109
+ *Radamés Roriz*
425
110
 
426
- Deprecations are reported as handled errors, with a severity of `:warning`.
111
+ * Fix `String#mb_chars` to not mutate the receiver.
427
112
 
428
- Useful to report deprecations happening in production to your bug tracker.
113
+ Previously it would call `force_encoding` on the receiver,
114
+ now it dups the receiver first.
429
115
 
430
- *Étienne Barrié*
431
-
432
- * Rename `Range#overlaps?` to `#overlap?` and add alias for backwards compatibility
433
-
434
- *Christian Schmidt*
435
-
436
- * Fix `EncryptedConfiguration` returning incorrect values for some `Hash`
437
- methods
438
-
439
- *Hartley McGuire*
440
-
441
- * Don't show secrets for `MessageEncryptor#inspect`.
442
-
443
- Before:
444
-
445
- ```ruby
446
- ActiveSupport::MessageEncryptor.new(secret, cipher: "aes-256-gcm").inspect
447
- "#<ActiveSupport::MessageEncryptor:0x0000000104888038 ... @secret=\"\\xAF\\bFh]LV}q\\nl\\xB2U\\xB3 ... >"
448
- ```
116
+ *Jean Boussier*
449
117
 
450
- After:
118
+ * Improve `ErrorSubscriber` to also mark error causes as reported.
451
119
 
452
- ```ruby
453
- ActiveSupport::MessageEncryptor.new(secret, cipher: "aes-256-gcm").inspect
454
- "#<ActiveSupport::MessageEncryptor:0x0000000104888038>"
455
- ```
120
+ This avoid some cases of errors being reported twice, notably in views because of how
121
+ errors are wrapped in `ActionView::Template::Error`.
456
122
 
457
- *Petrik de Heus*
123
+ *Jean Boussier*
458
124
 
459
- * Don't show contents for `EncryptedConfiguration#inspect`.
125
+ * Fix `Module#module_parent_name` to return the correct name after the module has been named.
460
126
 
461
- Before:
462
- ```ruby
463
- Rails.application.credentials.inspect
464
- "#<ActiveSupport::EncryptedConfiguration:0x000000010d2b38e8 ... @config={:secret=>\"something secret\"} ... @key_file_contents=\"915e4ea054e011022398dc242\" ...>"
465
- ```
127
+ When called on an anonymous module, the return value wouldn't change after the module was given a name
128
+ later by being assigned to a constant.
466
129
 
467
- After:
468
130
  ```ruby
469
- Rails.application.credentials.inspect
470
- "#<ActiveSupport::EncryptedConfiguration:0x000000010d2b38e8>"
131
+ mod = Module.new
132
+ mod.module_parent_name # => "Object"
133
+ MyModule::Something = mod
134
+ mod.module_parent_name # => "MyModule"
471
135
  ```
472
136
 
473
- *Petrik de Heus*
474
-
475
- * `ERB::Util.html_escape_once` always returns an `html_safe` string.
476
-
477
- This method previously maintained the `html_safe?` property of a string on the return
478
- value. Because this string has been escaped, however, not marking it as `html_safe` causes
479
- entities to be double-escaped.
480
-
481
- As an example, take this view snippet:
482
-
483
- ```html
484
- <p><%= html_escape_once("this & that &amp; the other") %></p>
485
- ```
486
-
487
- Before this change, that would be double-escaped and render as:
137
+ *Jean Boussier*
488
138
 
489
- ```html
490
- <p>this &amp;amp; that &amp;amp; the other</p>
491
- ```
139
+ * Fix a bug in `ERB::Util.tokenize` that causes incorrect tokenization when ERB tags are preceeded by multibyte characters.
492
140
 
493
- After this change, it renders correctly as:
141
+ *Martin Emde*
494
142
 
495
- ```html
496
- <p>this &amp; that &amp; the other</p>
497
- ```
498
143
 
499
- Fixes #48256
144
+ ## Rails 7.2.2.2 (August 13, 2025) ##
500
145
 
501
- *Mike Dalessio*
146
+ * No changes.
502
147
 
503
- * Deprecate `SafeBuffer#clone_empty`.
504
148
 
505
- This method has not been used internally since Rails 4.2.0.
149
+ ## Rails 7.2.2.1 (December 10, 2024) ##
506
150
 
507
- *Mike Dalessio*
151
+ * No changes.
508
152
 
509
- * `MessageEncryptor`, `MessageVerifier`, and `config.active_support.message_serializer`
510
- now accept `:message_pack` and `:message_pack_allow_marshal` as serializers.
511
- These serializers require the [`msgpack` gem](https://rubygems.org/gems/msgpack)
512
- (>= 1.7.0).
513
153
 
514
- The Message Pack format can provide improved performance and smaller payload
515
- sizes. It also supports round-tripping some Ruby types that are not supported
516
- by JSON. For example:
154
+ ## Rails 7.2.2 (October 30, 2024) ##
517
155
 
518
- ```ruby
519
- verifier = ActiveSupport::MessageVerifier.new("secret")
520
- data = [{ a: 1 }, { b: 2 }.with_indifferent_access, 1.to_d, Time.at(0, 123)]
521
- message = verifier.generate(data)
156
+ * Include options when instrumenting `ActiveSupport::Cache::Store#delete` and `ActiveSupport::Cache::Store#delete_multi`.
522
157
 
523
- # BEFORE with config.active_support.message_serializer = :json
524
- verifier.verified(message)
525
- # => [{"a"=>1}, {"b"=>2}, "1.0", "1969-12-31T18:00:00.000-06:00"]
526
- verifier.verified(message).map(&:class)
527
- # => [Hash, Hash, String, String]
158
+ *Adam Renberg Tamm*
528
159
 
529
- # AFTER with config.active_support.message_serializer = :message_pack
530
- verifier.verified(message)
531
- # => [{:a=>1}, {"b"=>2}, 0.1e1, 1969-12-31 18:00:00.000123 -0600]
532
- verifier.verified(message).map(&:class)
533
- # => [Hash, ActiveSupport::HashWithIndifferentAccess, BigDecimal, Time]
534
- ```
160
+ * Print test names when running `rails test -v` for parallel tests.
535
161
 
536
- The `:message_pack` serializer can fall back to deserializing with
537
- `ActiveSupport::JSON` when necessary, and the `:message_pack_allow_marshal`
538
- serializer can fall back to deserializing with `Marshal` as well as
539
- `ActiveSupport::JSON`. Additionally, the `:marshal`, `:json`, and
540
- `:json_allow_marshal` serializers can now fall back to deserializing with
541
- `ActiveSupport::MessagePack` when necessary. These behaviors ensure old
542
- messages can still be read so that migration is easier.
162
+ *John Hawthorn*, *Abeid Ahmed*
543
163
 
544
- *Jonathan Hefner*
545
164
 
546
- * A new `7.1` cache format is available which includes an optimization for
547
- bare string values such as view fragments.
165
+ ## Rails 7.2.1.2 (October 23, 2024) ##
548
166
 
549
- The `7.1` cache format is used by default for new apps, and existing apps
550
- can enable the format by setting `config.load_defaults 7.1` or by setting
551
- `config.active_support.cache_format_version = 7.1` in `config/application.rb`
552
- or a `config/environments/*.rb` file.
167
+ * No changes.
553
168
 
554
- Cache entries written using the `6.1` or `7.0` cache formats can be read
555
- when using the `7.1` format. To perform a rolling deploy of a Rails 7.1
556
- upgrade, wherein servers that have not yet been upgraded must be able to
557
- read caches from upgraded servers, leave the cache format unchanged on the
558
- first deploy, then enable the `7.1` cache format on a subsequent deploy.
559
169
 
560
- *Jonathan Hefner*
170
+ ## Rails 7.2.1.1 (October 15, 2024) ##
561
171
 
562
- * Active Support cache stores can now use a preconfigured serializer based on
563
- `ActiveSupport::MessagePack` via the `:serializer` option:
172
+ * No changes.
564
173
 
565
- ```ruby
566
- config.cache_store = :redis_cache_store, { serializer: :message_pack }
567
- ```
568
174
 
569
- The `:message_pack` serializer can reduce cache entry sizes and improve
570
- performance, but requires the [`msgpack` gem](https://rubygems.org/gems/msgpack)
571
- (>= 1.7.0).
175
+ ## Rails 7.2.1 (August 22, 2024) ##
572
176
 
573
- The `:message_pack` serializer can read cache entries written by the default
574
- serializer, and the default serializer can now read entries written by the
575
- `:message_pack` serializer. These behaviors make it easy to migrate between
576
- serializer without invalidating the entire cache.
177
+ * No changes.
577
178
 
578
- *Jonathan Hefner*
579
179
 
580
- * `Object#deep_dup` no longer duplicate named classes and modules.
180
+ ## Rails 7.2.0 (August 09, 2024) ##
581
181
 
582
- Before:
182
+ * Fix `delegate_missing_to allow_nil: true` when called with implict self
583
183
 
584
184
  ```ruby
585
- hash = { class: Object, module: Kernel }
586
- hash.deep_dup # => {:class=>#<Class:0x00000001063ffc80>, :module=>#<Module:0x00000001063ffa00>}
587
- ```
185
+ class Person
186
+ delegate_missing_to :address, allow_nil: true
588
187
 
589
- After:
188
+ def address
189
+ nil
190
+ end
590
191
 
591
- ```ruby
592
- hash = { class: Object, module: Kernel }
593
- hash.deep_dup # => {:class=>Object, :module=>Kernel}
192
+ def berliner?
193
+ city == "Berlin"
194
+ end
195
+ end
196
+
197
+ Person.new.city # => nil
198
+ Person.new.berliner? # undefined local variable or method `city' for an instance of Person (NameError)
594
199
  ```
595
200
 
596
201
  *Jean Boussier*
597
202
 
598
- * Consistently raise an `ArgumentError` if the `ActiveSupport::Cache` key is blank.
203
+ * Add `logger` as a dependency since it is a bundled gem candidate for Ruby 3.5
599
204
 
600
- *Joshua Young*
205
+ *Earlopain*
601
206
 
602
- * Deprecate usage of the singleton `ActiveSupport::Deprecation`.
207
+ * Define `Digest::UUID.nil_uuid`, which returns the so-called nil UUID.
603
208
 
604
- All usage of `ActiveSupport::Deprecation` as a singleton is deprecated, the most common one being
605
- `ActiveSupport::Deprecation.warn`. Gem authors should now create their own deprecator (`ActiveSupport::Deprecation`
606
- object), and use it to emit deprecation warnings.
209
+ *Xavier Noria*
607
210
 
608
- Calling any of the following without specifying a deprecator argument is also deprecated:
609
- * Module.deprecate
610
- * deprecate_constant
611
- * DeprecatedObjectProxy
612
- * DeprecatedInstanceVariableProxy
613
- * DeprecatedConstantProxy
614
- * deprecation-related test assertions
211
+ * Support `duration` type in `ActiveSupport::XmlMini`.
615
212
 
616
- Use of `ActiveSupport::Deprecation.silence` and configuration methods like `behavior=`, `disallowed_behavior=`,
617
- `disallowed_warnings=` should now be aimed at the [application's deprecators](https://api.rubyonrails.org/classes/Rails/Application.html#method-i-deprecators).
213
+ *heka1024*
618
214
 
619
- ```ruby
620
- Rails.application.deprecators.silence do
621
- # code that emits deprecation warnings
622
- end
623
- ```
215
+ * Remove deprecated `ActiveSupport::Notifications::Event#children` and `ActiveSupport::Notifications::Event#parent_of?`.
624
216
 
625
- If your gem has a Railtie or Engine, it's encouraged to add your deprecator to the application's deprecators, that
626
- way the deprecation related configuration options will apply to it as well, e.g.
627
- `config.active_support.report_deprecations` set to `false` in the production environment will also disable your
628
- deprecator.
629
-
630
- ```ruby
631
- initializer "my_gem.deprecator" do |app|
632
- app.deprecators[:my_gem] = MyGem.deprecator
633
- end
634
- ```
635
-
636
- *Étienne Barrié*
217
+ *Rafael Mendonça França*
637
218
 
638
- * Add `Object#with` to set and restore public attributes around a block
219
+ * Remove deprecated support to call the following methods without passing a deprecator:
639
220
 
640
- ```ruby
641
- client.timeout # => 5
642
- client.with(timeout: 1) do
643
- client.timeout # => 1
644
- end
645
- client.timeout # => 5
646
- ```
221
+ - `deprecate`
222
+ - `deprecate_constant`
223
+ - `ActiveSupport::Deprecation::DeprecatedObjectProxy.new`
224
+ - `ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new`
225
+ - `ActiveSupport::Deprecation::DeprecatedConstantProxy.new`
226
+ - `assert_deprecated`
227
+ - `assert_not_deprecated`
228
+ - `collect_deprecations`
647
229
 
648
- *Jean Boussier*
230
+ *Rafael Mendonça França*
649
231
 
650
- * Remove deprecated support to generate incorrect RFC 4122 UUIDs when providing a namespace ID that is not one of the
651
- constants defined on `Digest::UUID`.
232
+ * Remove deprecated `ActiveSupport::Deprecation` delegation to instance.
652
233
 
653
234
  *Rafael Mendonça França*
654
235
 
655
- * Deprecate `config.active_support.use_rfc4122_namespaced_uuids`.
236
+ * Remove deprecated `SafeBuffer#clone_empty`.
656
237
 
657
238
  *Rafael Mendonça França*
658
239
 
659
- * Remove implicit conversion of objects into `String` by `ActiveSupport::SafeBuffer`.
240
+ * Remove deprecated `#to_default_s` from `Array`, `Date`, `DateTime` and `Time`.
660
241
 
661
242
  *Rafael Mendonça França*
662
243
 
663
- * Remove deprecated `active_support/core_ext/range/include_time_with_zone` file.
244
+ * Remove deprecated support to passing `Dalli::Client` instances to `MemCacheStore`.
664
245
 
665
246
  *Rafael Mendonça França*
666
247
 
667
- * Deprecate `config.active_support.remove_deprecated_time_with_zone_name`.
248
+ * Remove deprecated `config.active_support.use_rfc4122_namespaced_uuids`.
668
249
 
669
250
  *Rafael Mendonça França*
670
251
 
671
- * Remove deprecated override of `ActiveSupport::TimeWithZone.name`.
252
+ * Remove deprecated `config.active_support.remove_deprecated_time_with_zone_name`.
672
253
 
673
254
  *Rafael Mendonça França*
674
255
 
675
- * Deprecate `config.active_support.disable_to_s_conversion`.
256
+ * Remove deprecated `config.active_support.disable_to_s_conversion`.
676
257
 
677
258
  *Rafael Mendonça França*
678
259
 
679
- * Remove deprecated option to passing a format to `#to_s` in `Array`, `Range`, `Date`, `DateTime`, `Time`,
680
- `BigDecimal`, `Float` and, `Integer`.
260
+ * Remove deprecated support to bolding log text with positional boolean in `ActiveSupport::LogSubscriber#color`.
681
261
 
682
262
  *Rafael Mendonça França*
683
263
 
684
- * Remove deprecated `ActiveSupport::PerThreadRegistry`.
264
+ * Remove deprecated constants `ActiveSupport::LogSubscriber::CLEAR` and `ActiveSupport::LogSubscriber::BOLD`.
685
265
 
686
266
  *Rafael Mendonça França*
687
267
 
688
- * Remove deprecated override of `Enumerable#sum`.
268
+ * Remove deprecated support for `config.active_support.cache_format_version = 6.1`.
689
269
 
690
270
  *Rafael Mendonça França*
691
271
 
692
- * Deprecated initializing a `ActiveSupport::Cache::MemCacheStore` with an instance of `Dalli::Client`.
272
+ * Remove deprecated `:pool_size` and `:pool_timeout` options for the cache storage.
693
273
 
694
- Deprecate the undocumented option of providing an already-initialized instance of `Dalli::Client` to `ActiveSupport::Cache::MemCacheStore`. Such clients could be configured with unrecognized options, which could lead to unexpected behavior. Instead, provide addresses as documented.
695
-
696
- *aledustet*
274
+ *Rafael Mendonça França*
697
275
 
698
- * Stub `Time.new()` in `TimeHelpers#travel_to`
276
+ * Warn on tests without assertions.
699
277
 
700
- ```ruby
701
- travel_to Time.new(2004, 11, 24) do
702
- # Inside the `travel_to` block `Time.new` is stubbed
703
- assert_equal 2004, Time.new.year
704
- end
705
- ```
278
+ `ActiveSupport::TestCase` now warns when tests do not run any assertions.
279
+ This is helpful in detecting broken tests that do not perform intended assertions.
706
280
 
707
281
  *fatkodima*
708
282
 
709
- * Raise `ActiveSupport::MessageEncryptor::InvalidMessage` from
710
- `ActiveSupport::MessageEncryptor#decrypt_and_verify` regardless of cipher.
711
- Previously, when a `MessageEncryptor` was using a non-AEAD cipher such as
712
- AES-256-CBC, a corrupt or tampered message would raise
713
- `ActiveSupport::MessageVerifier::InvalidSignature`. Now, all ciphers raise
714
- the same error:
715
-
716
- ```ruby
717
- encryptor = ActiveSupport::MessageEncryptor.new("x" * 32, cipher: "aes-256-gcm")
718
- message = encryptor.encrypt_and_sign("message")
719
- encryptor.decrypt_and_verify(message.next)
720
- # => raises ActiveSupport::MessageEncryptor::InvalidMessage
721
-
722
- encryptor = ActiveSupport::MessageEncryptor.new("x" * 32, cipher: "aes-256-cbc")
723
- message = encryptor.encrypt_and_sign("message")
724
- encryptor.decrypt_and_verify(message.next)
725
- # BEFORE:
726
- # => raises ActiveSupport::MessageVerifier::InvalidSignature
727
- # AFTER:
728
- # => raises ActiveSupport::MessageEncryptor::InvalidMessage
729
- ```
730
-
731
- *Jonathan Hefner*
732
-
733
- * Support `nil` original values when using `ActiveSupport::MessageVerifier#verify`.
734
- Previously, `MessageVerifier#verify` did not work with `nil` original
735
- values, though both `MessageVerifier#verified` and
736
- `MessageEncryptor#decrypt_and_verify` do:
737
-
738
- ```ruby
739
- encryptor = ActiveSupport::MessageEncryptor.new(secret)
740
- message = encryptor.encrypt_and_sign(nil)
741
-
742
- encryptor.decrypt_and_verify(message)
743
- # => nil
744
-
745
- verifier = ActiveSupport::MessageVerifier.new(secret)
746
- message = verifier.generate(nil)
747
-
748
- verifier.verified(message)
749
- # => nil
750
-
751
- verifier.verify(message)
752
- # BEFORE:
753
- # => raises ActiveSupport::MessageVerifier::InvalidSignature
754
- # AFTER:
755
- # => nil
756
- ```
757
-
758
- *Jonathan Hefner*
759
-
760
- * Maintain `html_safe?` on html_safe strings when sliced with `slice`, `slice!`, or `chr` method.
761
-
762
- Previously, `html_safe?` was only maintained when the html_safe strings were sliced
763
- with `[]` method. Now, `slice`, `slice!`, and `chr` methods will maintain `html_safe?` like `[]` method.
764
-
765
- ```ruby
766
- string = "<div>test</div>".html_safe
767
- string.slice(0, 1).html_safe? # => true
768
- string.slice!(0, 1).html_safe? # => true
769
- # maintain html_safe? after the slice!
770
- string.html_safe? # => true
771
- string.chr.html_safe? # => true
772
- ```
773
-
774
- *Michael Go*
775
-
776
- * Add `Object#in?` support for open ranges.
777
-
778
- ```ruby
779
- assert Date.today.in?(..Date.tomorrow)
780
- assert_not Date.today.in?(Date.tomorrow..)
781
- ```
782
-
783
- *Ignacio Galindo*
784
-
785
- * `config.i18n.raise_on_missing_translations = true` now raises on any missing translation.
786
-
787
- Previously it would only raise when called in a view or controller. Now it will raise
788
- anytime `I18n.t` is provided an unrecognised key.
789
-
790
- If you do not want this behaviour, you can customise the i18n exception handler. See the
791
- upgrading guide or i18n guide for more information.
283
+ * Support `hexBinary` type in `ActiveSupport::XmlMini`.
792
284
 
793
- *Alex Ghiculescu*
285
+ *heka1024*
794
286
 
795
- * `ActiveSupport::CurrentAttributes` now raises if a restricted attribute name is used.
287
+ * Deprecate `ActiveSupport::ProxyObject` in favor of Ruby's built-in `BasicObject`.
796
288
 
797
- Attributes such as `set` and `reset` cannot be used as they clash with the
798
- `CurrentAttributes` public API.
799
-
800
- *Alex Ghiculescu*
801
-
802
- * `HashWithIndifferentAccess#transform_keys` now takes a Hash argument, just
803
- as Ruby's `Hash#transform_keys` does.
804
-
805
- *Akira Matsuda*
806
-
807
- * `delegate` now defines method with proper arity when delegating to a Class.
808
- With this change, it defines faster method (3.5x faster with no argument).
809
- However, in order to gain this benefit, the delegation target method has to
810
- be defined before declaring the delegation.
811
-
812
- ```ruby
813
- # This defines 3.5 times faster method than before
814
- class C
815
- def self.x() end
816
- delegate :x, to: :class
817
- end
818
-
819
- class C
820
- # This works but silently falls back to old behavior because
821
- # `delegate` cannot find the definition of `x`
822
- delegate :x, to: :class
823
- def self.x() end
824
- end
825
- ```
826
-
827
- *Akira Matsuda*
289
+ *Earlopain*
828
290
 
829
- * `assert_difference` message now includes what changed.
291
+ * `stub_const` now accepts a `exists: false` parameter to allow stubbing missing constants.
830
292
 
831
- This makes it easier to debug non-obvious failures.
293
+ *Jean Boussier*
832
294
 
833
- Before:
295
+ * Make `ActiveSupport::BacktraceCleaner` copy filters and silencers on dup and clone.
834
296
 
835
- ```
836
- "User.count" didn't change by 32.
837
- Expected: 1611
838
- Actual: 1579
839
- ```
297
+ Previously the copy would still share the internal silencers and filters array,
298
+ causing state to leak.
840
299
 
841
- After:
300
+ *Jean Boussier*
842
301
 
843
- ```
844
- "User.count" didn't change by 32, but by 0.
845
- Expected: 1611
846
- Actual: 1579
847
- ```
302
+ * Updating Astana with Western Kazakhstan TZInfo identifier.
848
303
 
849
- *Alex Ghiculescu*
304
+ *Damian Nelson*
850
305
 
851
- * Add ability to match exception messages to `assert_raises` assertion
306
+ * Add filename support for `ActiveSupport::Logger.logger_outputs_to?`.
852
307
 
853
- Instead of this
854
308
  ```ruby
855
- error = assert_raises(ArgumentError) do
856
- perform_service(param: 'exception')
857
- end
858
- assert_match(/incorrect param/i, error.message)
309
+ logger = Logger.new('/var/log/rails.log')
310
+ ActiveSupport::Logger.logger_outputs_to?(logger, '/var/log/rails.log')
859
311
  ```
860
312
 
861
- you can now write this
862
- ```ruby
863
- assert_raises(ArgumentError, match: /incorrect param/i) do
864
- perform_service(param: 'exception')
865
- end
866
- ```
867
-
868
- *fatkodima*
869
-
870
- * Add `Rails.env.local?` shorthand for `Rails.env.development? || Rails.env.test?`.
871
-
872
- *DHH*
313
+ *Christian Schmidt*
873
314
 
874
- * `ActiveSupport::Testing::TimeHelpers` now accepts named `with_usec` argument
875
- to `freeze_time`, `travel`, and `travel_to` methods. Passing true prevents
876
- truncating the destination time with `change(usec: 0)`.
315
+ * Include `IPAddr#prefix` when serializing an `IPAddr` using the
316
+ `ActiveSupport::MessagePack` serializer.
877
317
 
878
- *KevSlashNull*, and *serprex*
318
+ This change is backward and forward compatible — old payloads can
319
+ still be read, and new payloads will be readable by older versions of Rails.
879
320
 
880
- * `ActiveSupport::CurrentAttributes.resets` now accepts a method name
321
+ *Taiki Komaba*
881
322
 
882
- The block API is still the recommended approach, but now both APIs are supported:
323
+ * Add `default:` support for `ActiveSupport::CurrentAttributes.attribute`.
883
324
 
884
325
  ```ruby
885
326
  class Current < ActiveSupport::CurrentAttributes
886
- resets { Time.zone = nil }
887
- resets :clear_time_zone
327
+ attribute :counter, default: 0
888
328
  end
889
329
  ```
890
330
 
891
- *Alex Ghiculescu*
892
-
893
- * Ensure `ActiveSupport::Testing::Isolation::Forking` closes pipes
894
-
895
- Previously, `Forking.run_in_isolation` opened two ends of a pipe. The fork
896
- process closed the read end, wrote to it, and then terminated (which
897
- presumably closed the file descriptors on its end). The parent process
898
- closed the write end, read from it, and returned, never closing the read
899
- end.
331
+ *Sean Doyle*
900
332
 
901
- This resulted in an accumulation of open file descriptors, which could
902
- cause errors if the limit is reached.
903
-
904
- *Sam Bostock*
905
-
906
- * Fix `Time#change` and `Time#advance` for times around the end of Daylight
907
- Saving Time.
908
-
909
- Previously, when `Time#change` or `Time#advance` constructed a time inside
910
- the final stretch of Daylight Saving Time (DST), the non-DST offset would
911
- always be chosen for local times:
912
-
913
- ```ruby
914
- # DST ended just before 2021-11-07 2:00:00 AM in US/Eastern.
915
- ENV["TZ"] = "US/Eastern"
916
-
917
- time = Time.local(2021, 11, 07, 00, 59, 59) + 1
918
- # => 2021-11-07 01:00:00 -0400
919
- time.change(day: 07)
920
- # => 2021-11-07 01:00:00 -0500
921
- time.advance(seconds: 0)
922
- # => 2021-11-07 01:00:00 -0500
923
-
924
- time = Time.local(2021, 11, 06, 01, 00, 00)
925
- # => 2021-11-06 01:00:00 -0400
926
- time.change(day: 07)
927
- # => 2021-11-07 01:00:00 -0500
928
- time.advance(days: 1)
929
- # => 2021-11-07 01:00:00 -0500
930
- ```
931
-
932
- And the DST offset would always be chosen for times with a `TimeZone`
933
- object:
934
-
935
- ```ruby
936
- Time.zone = "US/Eastern"
937
-
938
- time = Time.new(2021, 11, 07, 02, 00, 00, Time.zone) - 3600
939
- # => 2021-11-07 01:00:00 -0500
940
- time.change(day: 07)
941
- # => 2021-11-07 01:00:00 -0400
942
- time.advance(seconds: 0)
943
- # => 2021-11-07 01:00:00 -0400
944
-
945
- time = Time.new(2021, 11, 8, 01, 00, 00, Time.zone)
946
- # => 2021-11-08 01:00:00 -0500
947
- time.change(day: 07)
948
- # => 2021-11-07 01:00:00 -0400
949
- time.advance(days: -1)
950
- # => 2021-11-07 01:00:00 -0400
951
- ```
952
-
953
- Now, `Time#change` and `Time#advance` will choose the offset that matches
954
- the original time's offset when possible:
955
-
956
- ```ruby
957
- ENV["TZ"] = "US/Eastern"
958
-
959
- time = Time.local(2021, 11, 07, 00, 59, 59) + 1
960
- # => 2021-11-07 01:00:00 -0400
961
- time.change(day: 07)
962
- # => 2021-11-07 01:00:00 -0400
963
- time.advance(seconds: 0)
964
- # => 2021-11-07 01:00:00 -0400
965
-
966
- time = Time.local(2021, 11, 06, 01, 00, 00)
967
- # => 2021-11-06 01:00:00 -0400
968
- time.change(day: 07)
969
- # => 2021-11-07 01:00:00 -0400
970
- time.advance(days: 1)
971
- # => 2021-11-07 01:00:00 -0400
972
-
973
- Time.zone = "US/Eastern"
974
-
975
- time = Time.new(2021, 11, 07, 02, 00, 00, Time.zone) - 3600
976
- # => 2021-11-07 01:00:00 -0500
977
- time.change(day: 07)
978
- # => 2021-11-07 01:00:00 -0500
979
- time.advance(seconds: 0)
980
- # => 2021-11-07 01:00:00 -0500
981
-
982
- time = Time.new(2021, 11, 8, 01, 00, 00, Time.zone)
983
- # => 2021-11-08 01:00:00 -0500
984
- time.change(day: 07)
985
- # => 2021-11-07 01:00:00 -0500
986
- time.advance(days: -1)
987
- # => 2021-11-07 01:00:00 -0500
988
- ```
989
-
990
- *Kevin Hall*, *Takayoshi Nishida*, and *Jonathan Hefner*
991
-
992
- * Fix MemoryStore to preserve entries TTL when incrementing or decrementing
993
-
994
- This is to be more consistent with how MemCachedStore and RedisCacheStore behaves.
995
-
996
- *Jean Boussier*
997
-
998
- * `Rails.error.handle` and `Rails.error.record` filter now by multiple error classes.
333
+ * Yield instance to `Object#with` block.
999
334
 
1000
335
  ```ruby
1001
- Rails.error.handle(IOError, ArgumentError) do
1002
- 1 + '1' # raises TypeError
336
+ client.with(timeout: 5_000) do |c|
337
+ c.get("/commits")
1003
338
  end
1004
- 1 + 1 # TypeErrors are not IOErrors or ArgumentError, so this will *not* be handled
1005
339
  ```
1006
340
 
1007
- *Martin Spickermann*
1008
-
1009
- * `Class#subclasses` and `Class#descendants` now automatically filter reloaded classes.
341
+ *Sean Doyle*
1010
342
 
1011
- Previously they could return old implementations of reloadable classes that have been
1012
- dereferenced but not yet garbage collected.
343
+ * Use logical core count instead of physical core count to determine the
344
+ default number of workers when parallelizing tests.
1013
345
 
1014
- They now automatically filter such classes like `DescendantTracker#subclasses` and
1015
- `DescendantTracker#descendants`.
1016
-
1017
- *Jean Boussier*
1018
-
1019
- * `Rails.error.report` now marks errors as reported to avoid reporting them twice.
346
+ *Jonathan Hefner*
1020
347
 
1021
- In some cases, users might want to report errors explicitly with some extra context
1022
- before letting it bubble up.
348
+ * Fix `Time.now/DateTime.now/Date.today` to return results in a system timezone after `#travel_to`.
1023
349
 
1024
- This also allows to safely catch and report errors outside of the execution context.
350
+ There is a bug in the current implementation of #travel_to:
351
+ it remembers a timezone of its argument, and all stubbed methods start
352
+ returning results in that remembered timezone. However, the expected
353
+ behavior is to return results in a system timezone.
1025
354
 
1026
- *Jean Boussier*
355
+ *Aleksei Chernenkov*
1027
356
 
1028
- * Add `assert_error_reported` and `assert_no_error_reported`
357
+ * Add `ErrorReported#unexpected` to report precondition violations.
1029
358
 
1030
- Allows to easily asserts an error happened but was handled
359
+ For example:
1031
360
 
1032
361
  ```ruby
1033
- report = assert_error_reported(IOError) do
362
+ def edit
363
+ if published?
364
+ Rails.error.unexpected("[BUG] Attempting to edit a published article, that shouldn't be possible")
365
+ return false
366
+ end
1034
367
  # ...
1035
368
  end
1036
- assert_equal "Oops", report.error.message
1037
- assert_equal "admin", report.context[:section]
1038
- assert_equal :warning, report.severity
1039
- assert_predicate report, :handled?
1040
369
  ```
1041
370
 
1042
- *Jean Boussier*
1043
-
1044
- * `ActiveSupport::Deprecation` behavior callbacks can now receive the
1045
- deprecator instance as an argument. This makes it easier for such callbacks
1046
- to change their behavior based on the deprecator's state. For example,
1047
- based on the deprecator's `debug` flag.
1048
-
1049
- 3-arity and splat-args callbacks such as the following will now be passed
1050
- the deprecator instance as their third argument:
1051
-
1052
- * `->(message, callstack, deprecator) { ... }`
1053
- * `->(*args) { ... }`
1054
- * `->(message, *other_args) { ... }`
1055
-
1056
- 2-arity and 4-arity callbacks such as the following will continue to behave
1057
- the same as before:
1058
-
1059
- * `->(message, callstack) { ... }`
1060
- * `->(message, callstack, deprecation_horizon, gem_name) { ... }`
1061
- * `->(message, callstack, *deprecation_details) { ... }`
1062
-
1063
- *Jonathan Hefner*
1064
-
1065
- * `ActiveSupport::Deprecation#disallowed_warnings` now affects the instance on
1066
- which it is configured.
1067
-
1068
- This means that individual `ActiveSupport::Deprecation` instances can be
1069
- configured with their own disallowed warnings, and the global
1070
- `ActiveSupport::Deprecation.disallowed_warnings` now only affects the global
1071
- `ActiveSupport::Deprecation.warn`.
1072
-
1073
- **Before**
1074
-
1075
- ```ruby
1076
- ActiveSupport::Deprecation.disallowed_warnings = ["foo"]
1077
- deprecator = ActiveSupport::Deprecation.new("2.0", "MyCoolGem")
1078
- deprecator.disallowed_warnings = ["bar"]
1079
-
1080
- ActiveSupport::Deprecation.warn("foo") # => raise ActiveSupport::DeprecationException
1081
- ActiveSupport::Deprecation.warn("bar") # => print "DEPRECATION WARNING: bar"
1082
- deprecator.warn("foo") # => raise ActiveSupport::DeprecationException
1083
- deprecator.warn("bar") # => print "DEPRECATION WARNING: bar"
1084
- ```
1085
-
1086
- **After**
1087
-
1088
- ```ruby
1089
- ActiveSupport::Deprecation.disallowed_warnings = ["foo"]
1090
- deprecator = ActiveSupport::Deprecation.new("2.0", "MyCoolGem")
1091
- deprecator.disallowed_warnings = ["bar"]
1092
-
1093
- ActiveSupport::Deprecation.warn("foo") # => raise ActiveSupport::DeprecationException
1094
- ActiveSupport::Deprecation.warn("bar") # => print "DEPRECATION WARNING: bar"
1095
- deprecator.warn("foo") # => print "DEPRECATION WARNING: foo"
1096
- deprecator.warn("bar") # => raise ActiveSupport::DeprecationException
1097
- ```
1098
-
1099
- Note that global `ActiveSupport::Deprecation` methods such as `ActiveSupport::Deprecation.warn`
1100
- and `ActiveSupport::Deprecation.disallowed_warnings` have been deprecated.
1101
-
1102
- *Jonathan Hefner*
1103
-
1104
- * Add italic and underline support to `ActiveSupport::LogSubscriber#color`
1105
-
1106
- Previously, only bold text was supported via a positional argument.
1107
- This allows for bold, italic, and underline options to be specified
1108
- for colored logs.
1109
-
1110
- ```ruby
1111
- info color("Hello world!", :red, bold: true, underline: true)
1112
- ```
1113
-
1114
- *Gannon McGibbon*
1115
-
1116
- * Add `String#downcase_first` method.
1117
-
1118
- This method is the corollary of `String#upcase_first`.
1119
-
1120
- *Mark Schneider*
1121
-
1122
- * `thread_mattr_accessor` will call `.dup.freeze` on non-frozen default values.
1123
-
1124
- This provides a basic level of protection against different threads trying
1125
- to mutate a shared default object.
1126
-
1127
- *Jonathan Hefner*
1128
-
1129
- * Add `raise_on_invalid_cache_expiration_time` config to `ActiveSupport::Cache::Store`
1130
-
1131
- Specifies if an `ArgumentError` should be raised if `Rails.cache` `fetch` or
1132
- `write` are given an invalid `expires_at` or `expires_in` time.
1133
-
1134
- Options are `true`, and `false`. If `false`, the exception will be reported
1135
- as `handled` and logged instead. Defaults to `true` if `config.load_defaults >= 7.1`.
1136
-
1137
- *Trevor Turk*
1138
-
1139
- * `ActiveSupport::Cache::Store#fetch` now passes an options accessor to the block.
1140
-
1141
- It makes possible to override cache options:
1142
-
1143
- Rails.cache.fetch("3rd-party-token") do |name, options|
1144
- token = fetch_token_from_remote
1145
- # set cache's TTL to match token's TTL
1146
- options.expires_in = token.expires_in
1147
- token
1148
- end
1149
-
1150
- *Andrii Gladkyi*, *Jean Boussier*
1151
-
1152
- * `default` option of `thread_mattr_accessor` now applies through inheritance and
1153
- also across new threads.
1154
-
1155
- Previously, the `default` value provided was set only at the moment of defining
1156
- the attribute writer, which would cause the attribute to be uninitialized in
1157
- descendants and in other threads.
1158
-
1159
- Fixes #43312.
1160
-
1161
- *Thierry Deo*
1162
-
1163
- * Redis cache store is now compatible with redis-rb 5.0.
371
+ The above will raise an error in development and test, but only report the error in production.
1164
372
 
1165
373
  *Jean Boussier*
1166
374
 
1167
- * Add `skip_nil:` support to `ActiveSupport::Cache::Store#fetch_multi`.
1168
-
1169
- *Daniel Alfaro*
375
+ * Make the order of read_multi and write_multi notifications for `Cache::Store#fetch_multi` operations match the order they are executed in.
1170
376
 
1171
- * Add `quarter` method to date/time
377
+ *Adam Renberg Tamm*
1172
378
 
1173
- *Matt Swanson*
379
+ * Make return values of `Cache::Store#write` consistent.
1174
380
 
1175
- * Fix `NoMethodError` on custom `ActiveSupport::Deprecation` behavior.
381
+ The return value was not specified before. Now it returns `true` on a successful write,
382
+ `nil` if there was an error talking to the cache backend, and `false` if the write failed
383
+ for another reason (e.g. the key already exists and `unless_exist: true` was passed).
1176
384
 
1177
- `ActiveSupport::Deprecation.behavior=` was supposed to accept any object
1178
- that responds to `call`, but in fact its internal implementation assumed that
1179
- this object could respond to `arity`, so it was restricted to only `Proc` objects.
385
+ *Sander Verdonschot*
1180
386
 
1181
- This change removes this `arity` restriction of custom behaviors.
387
+ * Fix logged cache keys not always matching actual key used by cache action.
1182
388
 
1183
- *Ryo Nakamura*
1184
-
1185
- * Support `:url_safe` option for `MessageEncryptor`.
1186
-
1187
- The `MessageEncryptor` constructor now accepts a `:url_safe` option, similar
1188
- to the `MessageVerifier` constructor. When enabled, this option ensures
1189
- that messages use a URL-safe encoding.
389
+ *Hartley McGuire*
1190
390
 
1191
- *Jonathan Hefner*
391
+ * Improve error messages of `assert_changes` and `assert_no_changes`.
1192
392
 
1193
- * Add `url_safe` option to `ActiveSupport::MessageVerifier` initializer
393
+ `assert_changes` error messages now display objects with `.inspect` to make it easier
394
+ to differentiate nil from empty strings, strings from symbols, etc.
395
+ `assert_no_changes` error messages now surface the actual value.
1194
396
 
1195
- `ActiveSupport::MessageVerifier.new` now takes optional `url_safe` argument.
1196
- It can generate URL-safe strings by passing `url_safe: true`.
397
+ *pcreux*
1197
398
 
1198
- ```ruby
1199
- verifier = ActiveSupport::MessageVerifier.new(url_safe: true)
1200
- message = verifier.generate(data) # => URL-safe string
1201
- ```
399
+ * Fix `#to_fs(:human_size)` to correctly work with negative numbers.
1202
400
 
1203
- This option is `false` by default to be backwards compatible.
401
+ *Earlopain*
1204
402
 
1205
- *Shouichi Kamiya*
403
+ * Fix `BroadcastLogger#dup` so that it duplicates the logger's `broadcasts`.
1206
404
 
1207
- * Enable connection pooling by default for `MemCacheStore` and `RedisCacheStore`.
405
+ *Andrew Novoselac*
1208
406
 
1209
- If you want to disable connection pooling, set `:pool` option to `false` when configuring the cache store:
407
+ * Fix issue where `bootstrap.rb` overwrites the `level` of a `BroadcastLogger`'s `broadcasts`.
1210
408
 
1211
- ```ruby
1212
- config.cache_store = :mem_cache_store, "cache.example.com", pool: false
1213
- ```
409
+ *Andrew Novoselac*
1214
410
 
1215
- *fatkodima*
411
+ * Fix compatibility with the `semantic_logger` gem.
1216
412
 
1217
- * Add `force:` support to `ActiveSupport::Cache::Store#fetch_multi`.
413
+ The `semantic_logger` gem doesn't behave exactly like stdlib logger in that
414
+ `SemanticLogger#level` returns a Symbol while stdlib `Logger#level` returns an Integer.
1218
415
 
1219
- *fatkodima*
416
+ This caused the various `LogSubscriber` classes in Rails to break when assigned a
417
+ `SemanticLogger` instance.
1220
418
 
1221
- * Deprecated `:pool_size` and `:pool_timeout` options for configuring connection pooling in cache stores.
419
+ *Jean Boussier*, *ojab*
1222
420
 
1223
- Use `pool: true` to enable pooling with default settings:
421
+ * Fix MemoryStore to prevent race conditions when incrementing or decrementing.
1224
422
 
1225
- ```ruby
1226
- config.cache_store = :redis_cache_store, pool: true
1227
- ```
423
+ *Pierre Jambet*
1228
424
 
1229
- Or pass individual options via `:pool` option:
425
+ * Implement `HashWithIndifferentAccess#to_proc`.
1230
426
 
1231
- ```ruby
1232
- config.cache_store = :redis_cache_store, pool: { size: 10, timeout: 2 }
1233
- ```
427
+ Previously, calling `#to_proc` on `HashWithIndifferentAccess` object used inherited `#to_proc`
428
+ method from the `Hash` class, which was not able to access values using indifferent keys.
1234
429
 
1235
430
  *fatkodima*
1236
431
 
1237
- * Allow #increment and #decrement methods of `ActiveSupport::Cache::Store`
1238
- subclasses to set new values.
1239
-
1240
- Previously incrementing or decrementing an unset key would fail and return
1241
- nil. A default will now be assumed and the key will be created.
1242
-
1243
- *Andrej Blagojević*, *Eugene Kenny*
1244
-
1245
- * Add `skip_nil:` support to `RedisCacheStore`
1246
-
1247
- *Joey Paris*
1248
-
1249
- * `ActiveSupport::Cache::MemoryStore#write(name, val, unless_exist:true)` now
1250
- correctly writes expired keys.
1251
-
1252
- *Alan Savage*
1253
-
1254
- * `ActiveSupport::ErrorReporter` now accepts and forward a `source:` parameter.
1255
-
1256
- This allow libraries to signal the origin of the errors, and reporters
1257
- to easily ignore some sources.
1258
-
1259
- *Jean Boussier*
1260
-
1261
- * Fix and add protections for XSS in `ActionView::Helpers` and `ERB::Util`.
1262
-
1263
- Add the method `ERB::Util.xml_name_escape` to escape dangerous characters
1264
- in names of tags and names of attributes, following the specification of XML.
1265
-
1266
- *Álvaro Martín Fraguas*
1267
-
1268
- * Respect `ActiveSupport::Logger.new`'s `:formatter` keyword argument
1269
-
1270
- The stdlib `Logger::new` allows passing a `:formatter` keyword argument to
1271
- set the logger's formatter. Previously `ActiveSupport::Logger.new` ignored
1272
- that argument by always setting the formatter to an instance of
1273
- `ActiveSupport::Logger::SimpleFormatter`.
1274
-
1275
- *Steven Harman*
1276
-
1277
- * Deprecate preserving the pre-Ruby 2.4 behavior of `to_time`
1278
-
1279
- With Ruby 2.4+ the default for +to_time+ changed from converting to the
1280
- local system time to preserving the offset of the receiver. At the time Rails
1281
- supported older versions of Ruby so a compatibility layer was added to assist
1282
- in the migration process. From Rails 5.0 new applications have defaulted to
1283
- the Ruby 2.4+ behavior and since Rails 7.0 now only supports Ruby 2.7+
1284
- this compatibility layer can be safely removed.
1285
-
1286
- To minimize any noise generated the deprecation warning only appears when the
1287
- setting is configured to `false` as that is the only scenario where the
1288
- removal of the compatibility layer has any effect.
1289
-
1290
- *Andrew White*
1291
-
1292
- * `Pathname.blank?` only returns true for `Pathname.new("")`
1293
-
1294
- Previously it would end up calling `Pathname#empty?` which returned true
1295
- if the path existed and was an empty directory or file.
1296
-
1297
- That behavior was unlikely to be expected.
1298
-
1299
- *Jean Boussier*
1300
-
1301
- * Deprecate `Notification::Event`'s `#children` and `#parent_of?`
1302
-
1303
- *John Hawthorn*
1304
-
1305
- * Change the default serializer of `ActiveSupport::MessageVerifier` from
1306
- `Marshal` to `ActiveSupport::JSON` when using `config.load_defaults 7.1`.
1307
-
1308
- Messages serialized with `Marshal` can still be read, but new messages will
1309
- be serialized with `ActiveSupport::JSON`. For more information, see
1310
- https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer.
1311
-
1312
- *Saba Kiaei*, *David Buckley*, and *Jonathan Hefner*
1313
-
1314
- * Change the default serializer of `ActiveSupport::MessageEncryptor` from
1315
- `Marshal` to `ActiveSupport::JSON` when using `config.load_defaults 7.1`.
1316
-
1317
- Messages serialized with `Marshal` can still be read, but new messages will
1318
- be serialized with `ActiveSupport::JSON`. For more information, see
1319
- https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer.
1320
-
1321
- *Zack Deveau*, *Martin Gingras*, and *Jonathan Hefner*
1322
-
1323
- * Add `ActiveSupport::TestCase#stub_const` to stub a constant for the duration of a yield.
1324
-
1325
- *DHH*
1326
-
1327
- * Fix `ActiveSupport::EncryptedConfiguration` to be compatible with Psych 4
1328
-
1329
- *Stephen Sugden*
1330
-
1331
- * Improve `File.atomic_write` error handling
1332
-
1333
- *Daniel Pepper*
1334
-
1335
- * Fix `Class#descendants` and `DescendantsTracker#descendants` compatibility with Ruby 3.1.
1336
-
1337
- [The native `Class#descendants` was reverted prior to Ruby 3.1 release](https://bugs.ruby-lang.org/issues/14394#note-33),
1338
- but `Class#subclasses` was kept, breaking the feature detection.
1339
-
1340
- *Jean Boussier*
1341
-
1342
- Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/activesupport/CHANGELOG.md) for previous changes.
432
+ Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/activesupport/CHANGELOG.md) for previous changes.