activesupport 7.2.2.1 → 8.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +422 -145
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +73 -2
  5. data/lib/active_support/benchmark.rb +21 -0
  6. data/lib/active_support/benchmarkable.rb +3 -2
  7. data/lib/active_support/broadcast_logger.rb +61 -74
  8. data/lib/active_support/cache/file_store.rb +14 -4
  9. data/lib/active_support/cache/mem_cache_store.rb +30 -29
  10. data/lib/active_support/cache/memory_store.rb +11 -5
  11. data/lib/active_support/cache/null_store.rb +2 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +43 -34
  13. data/lib/active_support/cache/strategy/local_cache.rb +72 -27
  14. data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
  15. data/lib/active_support/cache.rb +88 -20
  16. data/lib/active_support/callbacks.rb +28 -13
  17. data/lib/active_support/class_attribute.rb +33 -0
  18. data/lib/active_support/code_generator.rb +9 -0
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
  20. data/lib/active_support/concurrency/share_lock.rb +0 -1
  21. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  22. data/lib/active_support/configurable.rb +34 -0
  23. data/lib/active_support/configuration_file.rb +15 -6
  24. data/lib/active_support/continuous_integration.rb +145 -0
  25. data/lib/active_support/core_ext/array/conversions.rb +3 -3
  26. data/lib/active_support/core_ext/array.rb +7 -7
  27. data/lib/active_support/core_ext/benchmark.rb +0 -15
  28. data/lib/active_support/core_ext/big_decimal.rb +1 -1
  29. data/lib/active_support/core_ext/class/attribute.rb +26 -20
  30. data/lib/active_support/core_ext/class.rb +2 -2
  31. data/lib/active_support/core_ext/date/conversions.rb +2 -0
  32. data/lib/active_support/core_ext/date.rb +5 -5
  33. data/lib/active_support/core_ext/date_and_time/compatibility.rb +0 -35
  34. data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
  35. data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
  36. data/lib/active_support/core_ext/date_time.rb +5 -5
  37. data/lib/active_support/core_ext/digest.rb +1 -1
  38. data/lib/active_support/core_ext/enumerable.rb +25 -8
  39. data/lib/active_support/core_ext/erb/util.rb +5 -5
  40. data/lib/active_support/core_ext/file.rb +1 -1
  41. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
  42. data/lib/active_support/core_ext/hash/except.rb +0 -12
  43. data/lib/active_support/core_ext/hash.rb +8 -8
  44. data/lib/active_support/core_ext/integer.rb +3 -3
  45. data/lib/active_support/core_ext/kernel.rb +3 -3
  46. data/lib/active_support/core_ext/module/attr_internal.rb +3 -4
  47. data/lib/active_support/core_ext/module/introspection.rb +3 -0
  48. data/lib/active_support/core_ext/module.rb +11 -11
  49. data/lib/active_support/core_ext/numeric.rb +3 -3
  50. data/lib/active_support/core_ext/object/json.rb +24 -11
  51. data/lib/active_support/core_ext/object/to_query.rb +7 -1
  52. data/lib/active_support/core_ext/object/try.rb +2 -2
  53. data/lib/active_support/core_ext/object.rb +13 -13
  54. data/lib/active_support/core_ext/pathname.rb +2 -2
  55. data/lib/active_support/core_ext/range/overlap.rb +3 -3
  56. data/lib/active_support/core_ext/range/sole.rb +17 -0
  57. data/lib/active_support/core_ext/range.rb +4 -4
  58. data/lib/active_support/core_ext/securerandom.rb +24 -8
  59. data/lib/active_support/core_ext/string/filters.rb +3 -3
  60. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  61. data/lib/active_support/core_ext/string/multibyte.rb +12 -3
  62. data/lib/active_support/core_ext/string/output_safety.rb +29 -13
  63. data/lib/active_support/core_ext/string.rb +13 -13
  64. data/lib/active_support/core_ext/symbol.rb +1 -1
  65. data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
  66. data/lib/active_support/core_ext/time/calculations.rb +7 -2
  67. data/lib/active_support/core_ext/time/compatibility.rb +2 -19
  68. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  69. data/lib/active_support/core_ext/time.rb +5 -5
  70. data/lib/active_support/current_attributes/test_helper.rb +2 -2
  71. data/lib/active_support/current_attributes.rb +27 -17
  72. data/lib/active_support/delegation.rb +25 -44
  73. data/lib/active_support/dependencies/interlock.rb +11 -5
  74. data/lib/active_support/dependencies.rb +6 -2
  75. data/lib/active_support/deprecation/reporting.rb +4 -21
  76. data/lib/active_support/deprecation.rb +1 -1
  77. data/lib/active_support/duration.rb +14 -10
  78. data/lib/active_support/editor.rb +70 -0
  79. data/lib/active_support/encrypted_configuration.rb +20 -2
  80. data/lib/active_support/error_reporter.rb +81 -4
  81. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  82. data/lib/active_support/event_reporter.rb +592 -0
  83. data/lib/active_support/evented_file_update_checker.rb +5 -2
  84. data/lib/active_support/execution_context.rb +75 -7
  85. data/lib/active_support/execution_wrapper.rb +1 -1
  86. data/lib/active_support/file_update_checker.rb +8 -6
  87. data/lib/active_support/gem_version.rb +4 -4
  88. data/lib/active_support/gzip.rb +1 -0
  89. data/lib/active_support/hash_with_indifferent_access.rb +61 -38
  90. data/lib/active_support/i18n_railtie.rb +19 -11
  91. data/lib/active_support/inflector/inflections.rb +34 -16
  92. data/lib/active_support/inflector/methods.rb +3 -3
  93. data/lib/active_support/inflector/transliterate.rb +6 -8
  94. data/lib/active_support/isolated_execution_state.rb +17 -17
  95. data/lib/active_support/json/decoding.rb +6 -4
  96. data/lib/active_support/json/encoding.rb +159 -21
  97. data/lib/active_support/lazy_load_hooks.rb +1 -1
  98. data/lib/active_support/log_subscriber.rb +2 -6
  99. data/lib/active_support/logger_thread_safe_level.rb +6 -3
  100. data/lib/active_support/message_encryptors.rb +54 -2
  101. data/lib/active_support/message_pack/extensions.rb +6 -1
  102. data/lib/active_support/message_verifier.rb +9 -0
  103. data/lib/active_support/message_verifiers.rb +57 -3
  104. data/lib/active_support/messages/rotation_coordinator.rb +9 -0
  105. data/lib/active_support/messages/rotator.rb +10 -0
  106. data/lib/active_support/multibyte/chars.rb +12 -2
  107. data/lib/active_support/multibyte.rb +4 -0
  108. data/lib/active_support/notifications/fanout.rb +64 -43
  109. data/lib/active_support/notifications/instrumenter.rb +1 -1
  110. data/lib/active_support/number_helper/number_converter.rb +1 -1
  111. data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
  112. data/lib/active_support/number_helper.rb +22 -0
  113. data/lib/active_support/railtie.rb +32 -9
  114. data/lib/active_support/structured_event_subscriber.rb +99 -0
  115. data/lib/active_support/subscriber.rb +0 -5
  116. data/lib/active_support/syntax_error_proxy.rb +7 -0
  117. data/lib/active_support/tagged_logging.rb +5 -0
  118. data/lib/active_support/test_case.rb +67 -6
  119. data/lib/active_support/testing/assertions.rb +118 -27
  120. data/lib/active_support/testing/autorun.rb +5 -0
  121. data/lib/active_support/testing/error_reporter_assertions.rb +17 -0
  122. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  123. data/lib/active_support/testing/isolation.rb +0 -2
  124. data/lib/active_support/testing/notification_assertions.rb +92 -0
  125. data/lib/active_support/testing/parallelization/server.rb +15 -2
  126. data/lib/active_support/testing/parallelization/worker.rb +9 -3
  127. data/lib/active_support/testing/parallelization.rb +25 -1
  128. data/lib/active_support/testing/tests_without_assertions.rb +1 -1
  129. data/lib/active_support/testing/time_helpers.rb +9 -4
  130. data/lib/active_support/time_with_zone.rb +36 -23
  131. data/lib/active_support/values/time_zone.rb +19 -10
  132. data/lib/active_support/xml_mini.rb +3 -2
  133. data/lib/active_support.rb +21 -9
  134. metadata +35 -16
  135. data/lib/active_support/core_ext/range/each.rb +0 -24
  136. data/lib/active_support/proxy_object.rb +0 -20
  137. data/lib/active_support/testing/strict_warnings.rb +0 -43
data/CHANGELOG.md CHANGED
@@ -1,284 +1,561 @@
1
- ## Rails 7.2.2.1 (December 10, 2024) ##
1
+ ## Rails 8.1.3 (March 24, 2026) ##
2
2
 
3
- * No changes.
3
+ * Fix `JSONGemCoderEncoder` to correctly serialize custom object hash keys.
4
4
 
5
+ When hash keys are custom objects whose `as_json` returns a Hash,
6
+ the encoder now calls `to_s` on the original key object instead of
7
+ on the `as_json` result.
5
8
 
6
- ## Rails 7.2.2 (October 30, 2024) ##
9
+ Before:
10
+ hash = {CustomKey.new(123) => "value"}
11
+ hash.to_json # => {"{:id=>123}":"value"}
7
12
 
8
- * Include options when instrumenting `ActiveSupport::Cache::Store#delete` and `ActiveSupport::Cache::Store#delete_multi`.
13
+ After:
14
+ hash.to_json # => {"custom_123":"value"}
9
15
 
10
- *Adam Renberg Tamm*
16
+ *Dan Sharp*
11
17
 
12
- * Print test names when running `rails test -v` for parallel tests.
18
+ * Fix inflections to better handle overlapping acronyms.
13
19
 
14
- *John Hawthorn*, *Abeid Ahmed*
20
+ ```ruby
21
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
22
+ inflect.acronym "USD"
23
+ inflect.acronym "USDC"
24
+ end
15
25
 
26
+ "USDC".underscore # => "usdc"
27
+ ```
16
28
 
17
- ## Rails 7.2.1.2 (October 23, 2024) ##
29
+ *Said Kaldybaev*
18
30
 
19
- * No changes.
31
+ * Silence Dalli 4.0+ warning when using `ActiveSupport::Cache::MemCacheStore`.
20
32
 
33
+ *zzak*
21
34
 
22
- ## Rails 7.2.1.1 (October 15, 2024) ##
23
35
 
24
- * No changes.
36
+ ## Rails 8.1.2.1 (March 23, 2026) ##
25
37
 
38
+ * Reject scientific notation in NumberConverter
26
39
 
27
- ## Rails 7.2.1 (August 22, 2024) ##
40
+ [CVE-2026-33176]
28
41
 
29
- * No changes.
42
+ *Jean Boussier*
30
43
 
44
+ * Fix `SafeBuffer#%` to preserve unsafe status
31
45
 
32
- ## Rails 7.2.0 (August 09, 2024) ##
46
+ [CVE-2026-33170]
33
47
 
34
- * Fix `delegate_missing_to allow_nil: true` when called with implict self
48
+ *Jean Boussier*
35
49
 
36
- ```ruby
37
- class Person
38
- delegate_missing_to :address, allow_nil: true
50
+ * Improve performance of NumberToDelimitedConverter
39
51
 
40
- def address
41
- nil
42
- end
52
+ [CVE-2026-33169]
43
53
 
44
- def berliner?
45
- city == "Berlin"
46
- end
47
- end
54
+ *Jean Boussier*
48
55
 
49
- Person.new.city # => nil
50
- Person.new.berliner? # undefined local variable or method `city' for an instance of Person (NameError)
51
- ```
56
+
57
+ ## Rails 8.1.2 (January 08, 2026) ##
58
+
59
+ * Make `delegate` and `delegate_missing_to` work in BasicObject subclasses.
60
+
61
+ *Rafael Mendonça França*
62
+
63
+ * Fix Inflectors when using a locale that fallbacks to `:en`.
64
+
65
+ *Said Kaldybaev*
66
+
67
+ * Fix `ActiveSupport::TimeWithZone#as_json` to consistently return UTF-8 strings.
68
+
69
+ Previously the returned string would sometime be encoded in US-ASCII, which in
70
+ some cases may be problematic.
71
+
72
+ Now the method consistently always return UTF-8 strings.
52
73
 
53
74
  *Jean Boussier*
54
75
 
55
- * Add `logger` as a dependency since it is a bundled gem candidate for Ruby 3.5
76
+ * Fix `TimeWithZone#xmlschema` when wrapping a `DateTime` instance in local time.
56
77
 
57
- *Earlopain*
78
+ Previously it would return an invalid time.
58
79
 
59
- * Define `Digest::UUID.nil_uuid`, which returns the so-called nil UUID.
80
+ *Dmytro Rymar*
60
81
 
61
- *Xavier Noria*
82
+ * Implement LocalCache strategy on `ActiveSupport::Cache::MemoryStore`. The memory store
83
+ needs to respond to the same interface as other cache stores (e.g. `ActiveSupport::NullStore`).
62
84
 
63
- * Support `duration` type in `ActiveSupport::XmlMini`.
85
+ *Mikey Gough*
64
86
 
65
- *heka1024*
87
+ * Fix `ActiveSupport::Inflector.humanize` with international characters.
66
88
 
67
- * Remove deprecated `ActiveSupport::Notifications::Event#children` and `ActiveSupport::Notifications::Event#parent_of?`.
89
+ ```ruby
90
+ ActiveSupport::Inflector.humanize("áÉÍÓÚ") # => "Áéíóú"
91
+ ActiveSupport::Inflector.humanize("аБВГДЕ") # => "Абвгде"
92
+ ```
68
93
 
69
- *Rafael Mendonça França*
94
+ *Jose Luis Duran*
70
95
 
71
- * Remove deprecated support to call the following methods without passing a deprecator:
72
96
 
73
- - `deprecate`
74
- - `deprecate_constant`
75
- - `ActiveSupport::Deprecation::DeprecatedObjectProxy.new`
76
- - `ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new`
77
- - `ActiveSupport::Deprecation::DeprecatedConstantProxy.new`
78
- - `assert_deprecated`
79
- - `assert_not_deprecated`
80
- - `collect_deprecations`
97
+ ## Rails 8.1.1 (October 28, 2025) ##
81
98
 
82
- *Rafael Mendonça França*
99
+ * No changes.
83
100
 
84
- * Remove deprecated `ActiveSupport::Deprecation` delegation to instance.
85
101
 
86
- *Rafael Mendonça França*
102
+ ## Rails 8.1.0 (October 22, 2025) ##
87
103
 
88
- * Remove deprecated `SafeBuffer#clone_empty`.
104
+ * Remove deprecated passing a Time object to `Time#since`.
89
105
 
90
106
  *Rafael Mendonça França*
91
107
 
92
- * Remove deprecated `#to_default_s` from `Array`, `Date`, `DateTime` and `Time`.
108
+ * Remove deprecated `Benchmark.ms` method. It is now defined in the `benchmark` gem.
93
109
 
94
110
  *Rafael Mendonça França*
95
111
 
96
- * Remove deprecated support to passing `Dalli::Client` instances to `MemCacheStore`.
112
+ * Remove deprecated addition for `Time` instances with `ActiveSupport::TimeWithZone`.
97
113
 
98
114
  *Rafael Mendonça França*
99
115
 
100
- * Remove deprecated `config.active_support.use_rfc4122_namespaced_uuids`.
116
+ * Remove deprecated support for `to_time` to preserve the system local time. It will now always preserve the receiver
117
+ timezone.
101
118
 
102
119
  *Rafael Mendonça França*
103
120
 
104
- * Remove deprecated `config.active_support.remove_deprecated_time_with_zone_name`.
121
+ * Deprecate `config.active_support.to_time_preserves_timezone`.
105
122
 
106
123
  *Rafael Mendonça França*
107
124
 
108
- * Remove deprecated `config.active_support.disable_to_s_conversion`.
125
+ * Standardize event name formatting in `assert_event_reported` error messages.
109
126
 
110
- *Rafael Mendonça França*
127
+ The event name in failure messages now uses `.inspect` (e.g., `name: "user.created"`)
128
+ to match `assert_events_reported` and provide type clarity between strings and symbols.
129
+ This only affects tests that assert on the failure message format itself.
111
130
 
112
- * Remove deprecated support to bolding log text with positional boolean in `ActiveSupport::LogSubscriber#color`.
131
+ *George Ma*
113
132
 
114
- *Rafael Mendonça França*
133
+ * Fix `Enumerable#sole` to return the full tuple instead of just the first element of the tuple.
115
134
 
116
- * Remove deprecated constants `ActiveSupport::LogSubscriber::CLEAR` and `ActiveSupport::LogSubscriber::BOLD`.
135
+ *Olivier Bellone*
117
136
 
118
- *Rafael Mendonça França*
137
+ * Fix parallel tests hanging when worker processes die abruptly.
119
138
 
120
- * Remove deprecated support for `config.active_support.cache_format_version = 6.1`.
139
+ Previously, if a worker process was killed (e.g., OOM killed, `kill -9`) during parallel
140
+ test execution, the test suite would hang forever waiting for the dead worker.
121
141
 
122
- *Rafael Mendonça França*
142
+ *Joshua Young*
123
143
 
124
- * Remove deprecated `:pool_size` and `:pool_timeout` options for the cache storage.
144
+ * Add `config.active_support.escape_js_separators_in_json`.
125
145
 
126
- *Rafael Mendonça França*
146
+ Introduce a new framework default to skip escaping LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029) in JSON.
127
147
 
128
- * Warn on tests without assertions.
148
+ Historically these characters were not valid inside JavaScript literal strings but that changed in ECMAScript 2019.
149
+ As such it's no longer a concern in modern browsers: https://caniuse.com/mdn-javascript_builtins_json_json_superset.
129
150
 
130
- `ActiveSupport::TestCase` now warns when tests do not run any assertions.
131
- This is helpful in detecting broken tests that do not perform intended assertions.
151
+ *Étienne Barrié*, *Jean Boussier*
132
152
 
133
- *fatkodima*
153
+ * Fix `NameError` when `class_attribute` is defined on instance singleton classes.
134
154
 
135
- * Support `hexBinary` type in `ActiveSupport::XmlMini`.
155
+ Previously, calling `class_attribute` on an instance's singleton class would raise
156
+ a `NameError` when accessing the attribute through the instance.
136
157
 
137
- *heka1024*
158
+ ```ruby
159
+ object = MyClass.new
160
+ object.singleton_class.class_attribute :foo, default: "bar"
161
+ object.foo # previously raised NameError, now returns "bar"
162
+ ```
138
163
 
139
- * Deprecate `ActiveSupport::ProxyObject` in favor of Ruby's built-in `BasicObject`.
164
+ *Joshua Young*
140
165
 
141
- *Earlopain*
166
+ * Introduce `ActiveSupport::Testing::EventReporterAssertions#with_debug_event_reporting`
167
+ to enable event reporter debug mode in tests.
142
168
 
143
- * `stub_const` now accepts a `exists: false` parameter to allow stubbing missing constants.
169
+ The previous way to enable debug mode is by using `#with_debug` on the
170
+ event reporter itself, which is too verbose. This new helper will help
171
+ clear up any confusion on how to test debug events.
144
172
 
145
- *Jean Boussier*
173
+ *Gannon McGibbon*
174
+
175
+ * Add `ActiveSupport::StructuredEventSubscriber` for consuming notifications and
176
+ emitting structured event logs. Events may be emitted with the `#emit_event`
177
+ or `#emit_debug_event` methods.
178
+
179
+ ```ruby
180
+ class MyStructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber
181
+ def notification(event)
182
+ emit_event("my.notification", data: 1)
183
+ end
184
+ end
185
+ ```
146
186
 
147
- * Make `ActiveSupport::BacktraceCleaner` copy filters and silencers on dup and clone.
187
+ *Adrianna Chang*
148
188
 
149
- Previously the copy would still share the internal silencers and filters array,
150
- causing state to leak.
189
+ * `ActiveSupport::FileUpdateChecker` does not depend on `Time.now` to prevent unecessary reloads with time travel test helpers
151
190
 
152
- *Jean Boussier*
191
+ *Jan Grodowski*
192
+
193
+ * Add `ActiveSupport::Cache::Store#namespace=` and `#namespace`.
194
+
195
+ Can be used as an alternative to `Store#clear` in some situations such as parallel
196
+ testing.
197
+
198
+ *Nick Schwaderer*
199
+
200
+ * Create `parallel_worker_id` helper for running parallel tests. This allows users to
201
+ know which worker they are currently running in.
202
+
203
+ *Nick Schwaderer*
204
+
205
+ * Make the cache of `ActiveSupport::Cache::Strategy::LocalCache::Middleware` updatable.
153
206
 
154
- * Updating Astana with Western Kazakhstan TZInfo identifier.
207
+ If the cache client at `Rails.cache` of a booted application changes, the corresponding
208
+ mounted middleware needs to update in order for request-local caches to be setup properly.
209
+ Otherwise, redundant cache operations will erroneously hit the datastore.
155
210
 
156
- *Damian Nelson*
211
+ *Gannon McGibbon*
157
212
 
158
- * Add filename support for `ActiveSupport::Logger.logger_outputs_to?`.
213
+ * Add `assert_events_reported` test helper for `ActiveSupport::EventReporter`.
214
+
215
+ This new assertion allows testing multiple events in a single block, regardless of order:
159
216
 
160
217
  ```ruby
161
- logger = Logger.new('/var/log/rails.log')
162
- ActiveSupport::Logger.logger_outputs_to?(logger, '/var/log/rails.log')
218
+ assert_events_reported([
219
+ { name: "user.created", payload: { id: 123 } },
220
+ { name: "email.sent", payload: { to: "user@example.com" } }
221
+ ]) do
222
+ create_user_and_send_welcome_email
223
+ end
224
+ ```
225
+
226
+ *George Ma*
227
+
228
+ * Add `ActiveSupport::TimeZone#standard_name` method.
229
+
230
+ ``` ruby
231
+ zone = ActiveSupport::TimeZone['Hawaii']
232
+ # Old way
233
+ ActiveSupport::TimeZone::MAPPING[zone.name]
234
+ # New way
235
+ zone.standard_name # => 'Pacific/Honolulu'
163
236
  ```
164
237
 
165
- *Christian Schmidt*
238
+ *Bogdan Gusiev*
166
239
 
167
- * Include `IPAddr#prefix` when serializing an `IPAddr` using the
168
- `ActiveSupport::MessagePack` serializer.
240
+ * Add Structured Event Reporter, accessible via `Rails.event`.
169
241
 
170
- This change is backward and forward compatible old payloads can
171
- still be read, and new payloads will be readable by older versions of Rails.
242
+ The Event Reporter provides a unified interface for producing structured events in Rails
243
+ applications:
172
244
 
173
- *Taiki Komaba*
245
+ ```ruby
246
+ Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")
247
+ ```
174
248
 
175
- * Add `default:` support for `ActiveSupport::CurrentAttributes.attribute`.
249
+ It supports adding tags to events:
176
250
 
177
251
  ```ruby
178
- class Current < ActiveSupport::CurrentAttributes
179
- attribute :counter, default: 0
252
+ Rails.event.tagged("graphql") do
253
+ # Event includes tags: { graphql: true }
254
+ Rails.event.notify("user.signup", user_id: 123, email: "user@example.com")
180
255
  end
181
256
  ```
182
257
 
183
- *Sean Doyle*
258
+ As well as context:
259
+ ```ruby
260
+ # All events will contain context: {request_id: "abc123", shop_id: 456}
261
+ Rails.event.set_context(request_id: "abc123", shop_id: 456)
262
+ ```
184
263
 
185
- * Yield instance to `Object#with` block.
264
+ Events are emitted to subscribers. Applications register subscribers to
265
+ control how events are serialized and emitted. Subscribers must implement
266
+ an `#emit` method, which receives the event hash:
186
267
 
187
268
  ```ruby
188
- client.with(timeout: 5_000) do |c|
189
- c.get("/commits")
269
+ class LogSubscriber
270
+ def emit(event)
271
+ payload = event[:payload].map { |key, value| "#{key}=#{value}" }.join(" ")
272
+ source_location = event[:source_location]
273
+ log = "[#{event[:name]}] #{payload} at #{source_location[:filepath]}:#{source_location[:lineno]}"
274
+ Rails.logger.info(log)
275
+ end
190
276
  end
191
277
  ```
192
278
 
193
- *Sean Doyle*
279
+ *Adrianna Chang*
194
280
 
195
- * Use logical core count instead of physical core count to determine the
196
- default number of workers when parallelizing tests.
281
+ * Make `ActiveSupport::Logger` `#freeze`-friendly.
197
282
 
198
- *Jonathan Hefner*
283
+ *Joshua Young*
199
284
 
200
- * Fix `Time.now/DateTime.now/Date.today` to return results in a system timezone after `#travel_to`.
285
+ * Make `ActiveSupport::Gzip.compress` deterministic based on input.
201
286
 
202
- There is a bug in the current implementation of #travel_to:
203
- it remembers a timezone of its argument, and all stubbed methods start
204
- returning results in that remembered timezone. However, the expected
205
- behavior is to return results in a system timezone.
287
+ `ActiveSupport::Gzip.compress` used to include a timestamp in the output,
288
+ causing consecutive calls with the same input data to have different output
289
+ if called during different seconds. It now always sets the timestamp to `0`
290
+ so that the output is identical for any given input.
206
291
 
207
- *Aleksei Chernenkov*
292
+ *Rob Brackett*
208
293
 
209
- * Add `ErrorReported#unexpected` to report precondition violations.
294
+ * Given an array of `Thread::Backtrace::Location` objects, the new method
295
+ `ActiveSupport::BacktraceCleaner#clean_locations` returns an array with the
296
+ clean ones:
297
+
298
+ ```ruby
299
+ clean_locations = backtrace_cleaner.clean_locations(caller_locations)
300
+ ```
210
301
 
211
- For example:
302
+ Filters and silencers receive strings as usual. However, the `path`
303
+ attributes of the locations in the returned array are the original,
304
+ unfiltered ones, since locations are immutable.
305
+
306
+ *Xavier Noria*
307
+
308
+ * Improve `CurrentAttributes` and `ExecutionContext` state managment in test cases.
309
+
310
+ Previously these two global state would be entirely cleared out whenever calling
311
+ into code that is wrapped by the Rails executor, typically Action Controller or
312
+ Active Job helpers:
212
313
 
213
314
  ```ruby
214
- def edit
215
- if published?
216
- Rails.error.unexpected("[BUG] Attempting to edit a published article, that shouldn't be possible")
217
- return false
218
- end
219
- # ...
315
+ test "#index works" do
316
+ CurrentUser.id = 42
317
+ get :index
318
+ CurrentUser.id == nil
220
319
  end
221
320
  ```
222
321
 
223
- The above will raise an error in development and test, but only report the error in production.
322
+ Now re-entering the executor properly save and restore that state.
224
323
 
225
324
  *Jean Boussier*
226
325
 
227
- * Make the order of read_multi and write_multi notifications for `Cache::Store#fetch_multi` operations match the order they are executed in.
326
+ * The new method `ActiveSupport::BacktraceCleaner#first_clean_location`
327
+ returns the first clean location of the caller's call stack, or `nil`.
328
+ Locations are `Thread::Backtrace::Location` objects. Useful when you want to
329
+ report the application-level location where something happened as an object.
228
330
 
229
- *Adam Renberg Tamm*
331
+ *Xavier Noria*
230
332
 
231
- * Make return values of `Cache::Store#write` consistent.
333
+ * FileUpdateChecker and EventedFileUpdateChecker ignore changes in Gem.path now.
232
334
 
233
- The return value was not specified before. Now it returns `true` on a successful write,
234
- `nil` if there was an error talking to the cache backend, and `false` if the write failed
235
- for another reason (e.g. the key already exists and `unless_exist: true` was passed).
335
+ *Ermolaev Andrey*, *zzak*
236
336
 
237
- *Sander Verdonschot*
337
+ * The new method `ActiveSupport::BacktraceCleaner#first_clean_frame` returns
338
+ the first clean frame of the caller's backtrace, or `nil`. Useful when you
339
+ want to report the application-level frame where something happened as a
340
+ string.
238
341
 
239
- * Fix logged cache keys not always matching actual key used by cache action.
342
+ *Xavier Noria*
240
343
 
241
- *Hartley McGuire*
344
+ * Always clear `CurrentAttributes` instances.
242
345
 
243
- * Improve error messages of `assert_changes` and `assert_no_changes`.
346
+ Previously `CurrentAttributes` instance would be reset at the end of requests.
347
+ Meaning its attributes would be re-initialized.
244
348
 
245
- `assert_changes` error messages now display objects with `.inspect` to make it easier
246
- to differentiate nil from empty strings, strings from symbols, etc.
247
- `assert_no_changes` error messages now surface the actual value.
349
+ This is problematic because it assume these objects don't hold any state
350
+ other than their declared attribute, which isn't always the case, and
351
+ can lead to state leak across request.
248
352
 
249
- *pcreux*
353
+ Now `CurrentAttributes` instances are abandoned at the end of a request,
354
+ and a new instance is created at the start of the next request.
250
355
 
251
- * Fix `#to_fs(:human_size)` to correctly work with negative numbers.
356
+ *Jean Boussier*, *Janko Marohnić*
252
357
 
253
- *Earlopain*
358
+ * Add public API for `before_fork_hook` in parallel testing.
254
359
 
255
- * Fix `BroadcastLogger#dup` so that it duplicates the logger's `broadcasts`.
360
+ Introduces a public API for calling the before fork hooks implemented by parallel testing.
256
361
 
257
- *Andrew Novoselac*
362
+ ```ruby
363
+ parallelize_before_fork do
364
+ # perform an action before test processes are forked
365
+ end
366
+ ```
367
+
368
+ *Eileen M. Uchitelle*
369
+
370
+ * Implement ability to skip creating parallel testing databases.
371
+
372
+ With parallel testing, Rails will create a database per process. If this isn't
373
+ desirable or you would like to implement databases handling on your own, you can
374
+ now turn off this default behavior.
375
+
376
+ To skip creating a database per process, you can change it via the
377
+ `parallelize` method:
258
378
 
259
- * Fix issue where `bootstrap.rb` overwrites the `level` of a `BroadcastLogger`'s `broadcasts`.
379
+ ```ruby
380
+ parallelize(workers: 10, parallelize_databases: false)
381
+ ```
382
+
383
+ or via the application configuration:
384
+
385
+ ```ruby
386
+ config.active_support.parallelize_databases = false
387
+ ```
388
+
389
+ *Eileen M. Uchitelle*
390
+
391
+ * Allow to configure maximum cache key sizes
392
+
393
+ When the key exceeds the configured limit (250 bytes by default), it will be truncated and
394
+ the digest of the rest of the key appended to it.
395
+
396
+ Note that previously `ActiveSupport::Cache::RedisCacheStore` allowed up to 1kb cache keys before
397
+ truncation, which is now reduced to 250 bytes.
398
+
399
+ ```ruby
400
+ config.cache_store = :redis_cache_store, { max_key_size: 64 }
401
+ ```
402
+
403
+ *fatkodima*
404
+
405
+ * Use `UNLINK` command instead of `DEL` in `ActiveSupport::Cache::RedisCacheStore` for non-blocking deletion.
406
+
407
+ *Aron Roh*
408
+
409
+ * Add `Cache#read_counter` and `Cache#write_counter`
410
+
411
+ ```ruby
412
+ Rails.cache.write_counter("foo", 1)
413
+ Rails.cache.read_counter("foo") # => 1
414
+ Rails.cache.increment("foo")
415
+ Rails.cache.read_counter("foo") # => 2
416
+ ```
417
+
418
+ *Alex Ghiculescu*
419
+
420
+ * Introduce ActiveSupport::Testing::ErrorReporterAssertions#capture_error_reports
421
+
422
+ Captures all reported errors from within the block that match the given
423
+ error class.
424
+
425
+ ```ruby
426
+ reports = capture_error_reports(IOError) do
427
+ Rails.error.report(IOError.new("Oops"))
428
+ Rails.error.report(IOError.new("Oh no"))
429
+ Rails.error.report(StandardError.new)
430
+ end
431
+
432
+ assert_equal 2, reports.size
433
+ assert_equal "Oops", reports.first.error.message
434
+ assert_equal "Oh no", reports.last.error.message
435
+ ```
260
436
 
261
437
  *Andrew Novoselac*
262
438
 
263
- * Fix compatibility with the `semantic_logger` gem.
439
+ * Introduce ActiveSupport::ErrorReporter#add_middleware
440
+
441
+ When reporting an error, the error context middleware will be called with the reported error
442
+ and base execution context. The stack may mutate the context hash. The mutated context will
443
+ then be passed to error subscribers. Middleware receives the same parameters as `ErrorReporter#report`.
444
+
445
+ *Andrew Novoselac*, *Sam Schmidt*
446
+
447
+ * Change execution wrapping to report all exceptions, including `Exception`.
448
+
449
+ If a more serious error like `SystemStackError` or `NoMemoryError` happens,
450
+ the error reporter should be able to report these kinds of exceptions.
451
+
452
+ *Gannon McGibbon*
453
+
454
+ * `ActiveSupport::Testing::Parallelization.before_fork_hook` allows declaration of callbacks that
455
+ are invoked immediately before forking test workers.
456
+
457
+ *Mike Dalessio*
458
+
459
+ * Allow the `#freeze_time` testing helper to accept a date or time argument.
460
+
461
+ ```ruby
462
+ Time.current # => Sun, 09 Jul 2024 15:34:49 EST -05:00
463
+ freeze_time Time.current + 1.day
464
+ sleep 1
465
+ Time.current # => Mon, 10 Jul 2024 15:34:49 EST -05:00
466
+ ```
467
+
468
+ *Joshua Young*
469
+
470
+ * `ActiveSupport::JSON` now accepts options
264
471
 
265
- The `semantic_logger` gem doesn't behave exactly like stdlib logger in that
266
- `SemanticLogger#level` returns a Symbol while stdlib `Logger#level` returns an Integer.
472
+ It is now possible to pass options to `ActiveSupport::JSON`:
473
+ ```ruby
474
+ ActiveSupport::JSON.decode('{"key": "value"}', symbolize_names: true) # => { key: "value" }
475
+ ```
476
+
477
+ *matthaigh27*
478
+
479
+ * `ActiveSupport::Testing::NotificationAssertions`'s `assert_notification` now matches against payload subsets by default.
480
+
481
+ Previously the following assertion would fail due to excess key vals in the notification payload. Now with payload subset matching, it will pass.
482
+
483
+ ```ruby
484
+ assert_notification("post.submitted", title: "Cool Post") do
485
+ ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: "Cool Body")
486
+ end
487
+ ```
488
+
489
+ Additionally, you can now persist a matched notification for more customized assertions.
490
+
491
+ ```ruby
492
+ notification = assert_notification("post.submitted", title: "Cool Post") do
493
+ ActiveSupport::Notifications.instrument("post.submitted", title: "Cool Post", body: Body.new("Cool Body"))
494
+ end
495
+
496
+ assert_instance_of(Body, notification.payload[:body])
497
+ ```
498
+
499
+ *Nicholas La Roux*
500
+
501
+ * Deprecate `String#mb_chars` and `ActiveSupport::Multibyte::Chars`.
502
+
503
+ These APIs are a relic of the Ruby 1.8 days when Ruby strings weren't encoding
504
+ aware. There is no legitimate reasons to need these APIs today.
505
+
506
+ *Jean Boussier*
507
+
508
+ * Deprecate `ActiveSupport::Configurable`
267
509
 
268
- This caused the various `LogSubscriber` classes in Rails to break when assigned a
269
- `SemanticLogger` instance.
510
+ *Sean Doyle*
511
+
512
+ * `nil.to_query("key")` now returns `key`.
513
+
514
+ Previously it would return `key=`, preventing round tripping with `Rack::Utils.parse_nested_query`.
515
+
516
+ *Erol Fornoles*
517
+
518
+ * Avoid wrapping redis in a `ConnectionPool` when using `ActiveSupport::Cache::RedisCacheStore` if the `:redis`
519
+ option is already a `ConnectionPool`.
520
+
521
+ *Joshua Young*
270
522
 
271
- *Jean Boussier*, *ojab*
523
+ * Alter `ERB::Util.tokenize` to return :PLAIN token with full input string when string doesn't contain ERB tags.
272
524
 
273
- * Fix MemoryStore to prevent race conditions when incrementing or decrementing.
525
+ *Martin Emde*
274
526
 
275
- *Pierre Jambet*
527
+ * Fix a bug in `ERB::Util.tokenize` that causes incorrect tokenization when ERB tags are preceded by multibyte characters.
276
528
 
277
- * Implement `HashWithIndifferentAccess#to_proc`.
529
+ *Martin Emde*
278
530
 
279
- Previously, calling `#to_proc` on `HashWithIndifferentAccess` object used inherited `#to_proc`
280
- method from the `Hash` class, which was not able to access values using indifferent keys.
531
+ * Add `ActiveSupport::Testing::NotificationAssertions` module to help with testing `ActiveSupport::Notifications`.
532
+
533
+ *Nicholas La Roux*, *Yishu See*, *Sean Doyle*
534
+
535
+ * `ActiveSupport::CurrentAttributes#attributes` now will return a new hash object on each call.
536
+
537
+ Previously, the same hash object was returned each time that method was called.
281
538
 
282
539
  *fatkodima*
283
540
 
284
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/activesupport/CHANGELOG.md) for previous changes.
541
+ * `ActiveSupport::JSON.encode` supports CIDR notation.
542
+
543
+ Previously:
544
+
545
+ ```ruby
546
+ ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0\""
547
+ ```
548
+
549
+ After this change:
550
+
551
+ ```ruby
552
+ ActiveSupport::JSON.encode(IPAddr.new("172.16.0.0/24")) # => "\"172.16.0.0/24\""
553
+ ```
554
+
555
+ *Taketo Takashima*
556
+
557
+ * Make `ActiveSupport::FileUpdateChecker` faster when checking many file-extensions.
558
+
559
+ *Jonathan del Strother*
560
+
561
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/activesupport/CHANGELOG.md) for previous changes.