activerecord 8.0.2 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +555 -388
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +1 -1
  5. data/lib/active_record/associations/association.rb +1 -1
  6. data/lib/active_record/associations/belongs_to_association.rb +11 -1
  7. data/lib/active_record/associations/builder/association.rb +16 -5
  8. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  9. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  10. data/lib/active_record/associations/builder/has_one.rb +1 -1
  11. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  12. data/lib/active_record/associations/collection_association.rb +3 -3
  13. data/lib/active_record/associations/collection_proxy.rb +22 -4
  14. data/lib/active_record/associations/deprecation.rb +88 -0
  15. data/lib/active_record/associations/errors.rb +3 -0
  16. data/lib/active_record/associations/join_dependency.rb +2 -0
  17. data/lib/active_record/associations/preloader/branch.rb +1 -0
  18. data/lib/active_record/associations.rb +159 -21
  19. data/lib/active_record/attribute_methods/query.rb +34 -0
  20. data/lib/active_record/attribute_methods/serialization.rb +17 -4
  21. data/lib/active_record/attribute_methods/time_zone_conversion.rb +10 -2
  22. data/lib/active_record/attribute_methods.rb +1 -1
  23. data/lib/active_record/attributes.rb +38 -24
  24. data/lib/active_record/autosave_association.rb +2 -2
  25. data/lib/active_record/base.rb +2 -4
  26. data/lib/active_record/coders/json.rb +14 -5
  27. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +2 -4
  28. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -3
  29. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -12
  30. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +413 -76
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +55 -40
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -9
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
  34. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
  35. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +26 -34
  36. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  37. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +89 -23
  38. data/lib/active_record/connection_adapters/abstract/transaction.rb +25 -3
  39. data/lib/active_record/connection_adapters/abstract_adapter.rb +89 -21
  40. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +43 -13
  41. data/lib/active_record/connection_adapters/column.rb +17 -4
  42. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  43. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  44. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
  45. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +26 -4
  46. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +27 -22
  47. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -2
  48. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  49. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -17
  50. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
  51. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  52. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  53. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +8 -6
  54. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +8 -21
  55. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +67 -31
  56. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +81 -48
  57. data/lib/active_record/connection_adapters/postgresql_adapter.rb +25 -9
  58. data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
  59. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -27
  60. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
  61. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -13
  62. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +58 -34
  63. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +4 -3
  64. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
  65. data/lib/active_record/connection_adapters.rb +1 -0
  66. data/lib/active_record/connection_handling.rb +15 -10
  67. data/lib/active_record/core.rb +13 -10
  68. data/lib/active_record/counter_cache.rb +33 -8
  69. data/lib/active_record/database_configurations/database_config.rb +5 -1
  70. data/lib/active_record/database_configurations/hash_config.rb +59 -9
  71. data/lib/active_record/database_configurations/url_config.rb +13 -3
  72. data/lib/active_record/database_configurations.rb +7 -3
  73. data/lib/active_record/delegated_type.rb +2 -2
  74. data/lib/active_record/dynamic_matchers.rb +54 -69
  75. data/lib/active_record/encryption/encryptable_record.rb +5 -5
  76. data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
  77. data/lib/active_record/encryption/encryptor.rb +39 -25
  78. data/lib/active_record/encryption/scheme.rb +1 -1
  79. data/lib/active_record/enum.rb +37 -20
  80. data/lib/active_record/errors.rb +23 -7
  81. data/lib/active_record/explain.rb +1 -1
  82. data/lib/active_record/explain_registry.rb +51 -2
  83. data/lib/active_record/filter_attribute_handler.rb +73 -0
  84. data/lib/active_record/fixture_set/table_row.rb +19 -2
  85. data/lib/active_record/fixtures.rb +2 -2
  86. data/lib/active_record/gem_version.rb +2 -2
  87. data/lib/active_record/inheritance.rb +1 -1
  88. data/lib/active_record/insert_all.rb +12 -7
  89. data/lib/active_record/locking/optimistic.rb +7 -0
  90. data/lib/active_record/locking/pessimistic.rb +5 -0
  91. data/lib/active_record/log_subscriber.rb +2 -6
  92. data/lib/active_record/middleware/shard_selector.rb +34 -17
  93. data/lib/active_record/migration/command_recorder.rb +14 -1
  94. data/lib/active_record/migration/compatibility.rb +34 -24
  95. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  96. data/lib/active_record/migration.rb +31 -21
  97. data/lib/active_record/model_schema.rb +36 -10
  98. data/lib/active_record/nested_attributes.rb +2 -0
  99. data/lib/active_record/persistence.rb +34 -3
  100. data/lib/active_record/query_cache.rb +22 -15
  101. data/lib/active_record/query_logs.rb +7 -7
  102. data/lib/active_record/querying.rb +4 -4
  103. data/lib/active_record/railtie.rb +34 -5
  104. data/lib/active_record/railties/controller_runtime.rb +11 -6
  105. data/lib/active_record/railties/databases.rake +23 -19
  106. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  107. data/lib/active_record/railties/job_runtime.rb +10 -11
  108. data/lib/active_record/reflection.rb +35 -0
  109. data/lib/active_record/relation/batches.rb +25 -11
  110. data/lib/active_record/relation/calculations.rb +35 -25
  111. data/lib/active_record/relation/delegation.rb +0 -1
  112. data/lib/active_record/relation/finder_methods.rb +41 -24
  113. data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
  114. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -7
  115. data/lib/active_record/relation/predicate_builder.rb +9 -7
  116. data/lib/active_record/relation/query_attribute.rb +3 -1
  117. data/lib/active_record/relation/query_methods.rb +44 -33
  118. data/lib/active_record/relation/spawn_methods.rb +6 -6
  119. data/lib/active_record/relation/where_clause.rb +9 -10
  120. data/lib/active_record/relation.rb +38 -16
  121. data/lib/active_record/result.rb +44 -21
  122. data/lib/active_record/runtime_registry.rb +41 -58
  123. data/lib/active_record/sanitization.rb +2 -0
  124. data/lib/active_record/schema_dumper.rb +12 -10
  125. data/lib/active_record/scoping.rb +0 -1
  126. data/lib/active_record/secure_token.rb +3 -3
  127. data/lib/active_record/signed_id.rb +46 -18
  128. data/lib/active_record/statement_cache.rb +13 -9
  129. data/lib/active_record/store.rb +44 -19
  130. data/lib/active_record/structured_event_subscriber.rb +85 -0
  131. data/lib/active_record/table_metadata.rb +5 -20
  132. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  133. data/lib/active_record/tasks/database_tasks.rb +44 -45
  134. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -40
  135. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  136. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
  137. data/lib/active_record/test_databases.rb +14 -4
  138. data/lib/active_record/test_fixtures.rb +27 -2
  139. data/lib/active_record/testing/query_assertions.rb +8 -2
  140. data/lib/active_record/timestamp.rb +4 -2
  141. data/lib/active_record/transaction.rb +2 -5
  142. data/lib/active_record/transactions.rb +34 -10
  143. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  144. data/lib/active_record/type/internal/timezone.rb +7 -0
  145. data/lib/active_record/type/json.rb +15 -2
  146. data/lib/active_record/type/serialized.rb +11 -4
  147. data/lib/active_record/type/type_map.rb +1 -1
  148. data/lib/active_record/type_caster/connection.rb +2 -1
  149. data/lib/active_record/validations/associated.rb +1 -1
  150. data/lib/active_record.rb +68 -5
  151. data/lib/arel/alias_predication.rb +2 -0
  152. data/lib/arel/crud.rb +8 -11
  153. data/lib/arel/delete_manager.rb +5 -0
  154. data/lib/arel/nodes/count.rb +2 -2
  155. data/lib/arel/nodes/delete_statement.rb +4 -2
  156. data/lib/arel/nodes/function.rb +4 -10
  157. data/lib/arel/nodes/named_function.rb +2 -2
  158. data/lib/arel/nodes/node.rb +1 -1
  159. data/lib/arel/nodes/update_statement.rb +4 -2
  160. data/lib/arel/nodes.rb +0 -2
  161. data/lib/arel/select_manager.rb +13 -4
  162. data/lib/arel/update_manager.rb +5 -0
  163. data/lib/arel/visitors/dot.rb +2 -3
  164. data/lib/arel/visitors/postgresql.rb +55 -0
  165. data/lib/arel/visitors/sqlite.rb +55 -8
  166. data/lib/arel/visitors/to_sql.rb +5 -21
  167. data/lib/arel.rb +3 -1
  168. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  169. metadata +16 -12
  170. data/lib/active_record/explain_subscriber.rb +0 -34
  171. data/lib/active_record/normalization.rb +0 -163
data/CHANGELOG.md CHANGED
@@ -1,667 +1,834 @@
1
- ## Rails 8.0.2 (March 12, 2025) ##
1
+ ## Rails 8.1.0 (October 22, 2025) ##
2
2
 
3
- * No changes.
3
+ * Fix SQLite3 data loss during table alterations with CASCADE foreign keys.
4
4
 
5
+ When altering a table in SQLite3 that is referenced by child tables with
6
+ `ON DELETE CASCADE` foreign keys, ActiveRecord would silently delete all
7
+ data from the child tables. This occurred because SQLite requires table
8
+ recreation for schema changes, and during this process the original table
9
+ is temporarily dropped, triggering CASCADE deletes on child tables.
5
10
 
6
- ## Rails 8.0.2 (March 12, 2025) ##
11
+ The root cause was incorrect ordering of operations. The original code
12
+ wrapped `disable_referential_integrity` inside a transaction, but
13
+ `PRAGMA foreign_keys` cannot be modified inside a transaction in SQLite -
14
+ attempting to do so simply has no effect. This meant foreign keys remained
15
+ enabled during table recreation, causing CASCADE deletes to fire.
7
16
 
8
- * Fix inverting `rename_enum_value` when `:from`/`:to` are provided.
17
+ The fix reverses the order to follow the official SQLite 12-step ALTER TABLE
18
+ procedure: `disable_referential_integrity` now wraps the transaction instead
19
+ of being wrapped by it. This ensures foreign keys are properly disabled
20
+ before the transaction starts and re-enabled after it commits, preventing
21
+ CASCADE deletes while maintaining data integrity through atomic transactions.
9
22
 
10
- *fatkodima*
11
-
12
- * Prevent persisting invalid record.
13
-
14
- *Edouard Chin*
23
+ *Ruy Rocha*
15
24
 
16
- * Fix inverting `drop_table` without options.
25
+ * Add replicas to test database parallelization setup.
17
26
 
18
- *fatkodima*
27
+ Setup and configuration of databases for parallel testing now includes replicas.
19
28
 
20
- * Fix count with group by qualified name on loaded relation.
29
+ This fixes an issue when using a replica database, database selector middleware,
30
+ and non-transactional tests, where integration tests running in parallel would select
31
+ the base test database, i.e. `db_test`, instead of the numbered parallel worker database,
32
+ i.e. `db_test_{n}`.
21
33
 
22
- *Ryuta Kamizono*
34
+ *Adam Maas*
23
35
 
24
- * Fix `sum` with qualified name on loaded relation.
36
+ * Support virtual (not persisted) generated columns on PostgreSQL 18+
25
37
 
26
- *Chris Gunther*
38
+ PostgreSQL 18 introduces virtual (not persisted) generated columns,
39
+ which are now the default unless the `stored: true` option is explicitly specified on PostgreSQL 18+.
27
40
 
28
- * The SQLite3 adapter quotes non-finite Numeric values like "Infinity" and "NaN".
41
+ ```ruby
42
+ create_table :users do |t|
43
+ t.string :name
44
+ t.virtual :lower_name, type: :string, as: "LOWER(name)", stored: false
45
+ t.virtual :name_length, type: :integer, as: "LENGTH(name)"
46
+ end
47
+ ```
29
48
 
30
- *Mike Dalessio*
49
+ *Yasuo Honda*
31
50
 
32
- * Handle libpq returning a database version of 0 on no/bad connection in `PostgreSQLAdapter`.
51
+ * Optimize schema dumping to prevent duplicate file generation.
33
52
 
34
- Before, this version would be cached and an error would be raised during connection configuration when
35
- comparing it with the minimum required version for the adapter. This meant that the connection could
36
- never be successfully configured on subsequent reconnection attempts.
53
+ `ActiveRecord::Tasks::DatabaseTasks.dump_all` now tracks which schema files
54
+ have already been dumped and skips dumping the same file multiple times.
55
+ This improves performance when multiple database configurations share the
56
+ same schema dump path.
37
57
 
38
- Now, this is treated as a connection failure consistent with libpq, raising a `ActiveRecord::ConnectionFailed`
39
- and ensuring the version isn't cached, which allows the version to be retrieved on the next connection attempt.
58
+ *Mikey Gough*, *Hartley McGuire*
40
59
 
41
- *Joshua Young*, *Rian McGuire*
60
+ * Add structured events for Active Record:
61
+ - `active_record.strict_loading_violation`
62
+ - `active_record.sql`
42
63
 
43
- * Fix error handling during connection configuration.
64
+ *Gannon McGibbon*
44
65
 
45
- Active Record wasn't properly handling errors during the connection configuration phase.
46
- This could lead to a partially configured connection being used, resulting in various exceptions,
47
- the most common being with the PostgreSQLAdapter raising `undefined method `key?' for nil`
48
- or `TypeError: wrong argument type nil (expected PG::TypeMap)`.
66
+ * Add support for integer shard keys.
67
+ ```ruby
68
+ # Now accepts symbols as shard keys.
69
+ ActiveRecord::Base.connects_to(shards: {
70
+ 1: { writing: :primary_shard_one, reading: :primary_shard_one },
71
+ 2: { writing: :primary_shard_two, reading: :primary_shard_two},
72
+ })
49
73
 
50
- *Jean Boussier*
74
+ ActiveRecord::Base.connected_to(shard: 1) do
75
+ # ..
76
+ end
77
+ ```
51
78
 
52
- * Fix a case where a non-retryable query could be marked retryable.
79
+ *Nony Dutton*
53
80
 
54
- *Hartley McGuire*
81
+ * Add `ActiveRecord::Base.only_columns`
55
82
 
56
- * Handle circular references when autosaving associations.
83
+ Similar in use case to `ignored_columns` but listing columns to consider rather than the ones
84
+ to ignore.
57
85
 
58
- *zzak*
86
+ Can be useful when working with a legacy or shared database schema, or to make safe schema change
87
+ in two deploys rather than three.
59
88
 
60
- * PoolConfig no longer keeps a reference to the connection class.
89
+ *Anton Kandratski*
61
90
 
62
- Keeping a reference to the class caused subtle issues when combined with reloading in
63
- development. Fixes #54343.
91
+ * Use `PG::Connection#close_prepared` (protocol level Close) to deallocate
92
+ prepared statements when available.
64
93
 
65
- *Mike Dalessio*
94
+ To enable its use, you must have pg >= 1.6.0, libpq >= 17, and a PostgreSQL
95
+ database version >= 17.
66
96
 
67
- * Fix SQL notifications sometimes not sent when using async queries.
97
+ *Hartley McGuire*, *Andrew Jackson*
68
98
 
69
- ```ruby
70
- Post.async_count
71
- ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) do
72
- Post.count
73
- end
74
- ```
99
+ * Fix query cache for pinned connections in multi threaded transactional tests
75
100
 
76
- In rare circumstances and under the right race condition, Active Support notifications
77
- would no longer be dispatched after using an asynchronous query.
78
- This is now fixed.
101
+ When a pinned connection is used across separate threads, they now use a separate cache store
102
+ for each thread.
79
103
 
80
- *Edouard Chin*
104
+ This improve accuracy of system tests, and any test using multiple threads.
81
105
 
82
- * Fix support for PostgreSQL enum types with commas in their name.
106
+ *Heinrich Lee Yu*, *Jean Boussier*
83
107
 
84
- *Arthur Hess*
108
+ * Fix time attribute dirty tracking with timezone conversions.
85
109
 
86
- * Fix inserts on MySQL with no RETURNING support for a table with multiple auto populated columns.
110
+ Time-only attributes now maintain a fixed date of 2000-01-01 during timezone conversions,
111
+ preventing them from being incorrectly marked as changed due to date shifts.
87
112
 
88
- *Nikita Vasilevsky*
113
+ This fixes an issue where time attributes would be marked as changed when setting the same time value
114
+ due to timezone conversion causing internal date shifts.
89
115
 
90
- * Fix joining on a scoped association with string joins and bind parameters.
116
+ *Prateek Choudhary*
91
117
 
92
- ```ruby
93
- class Instructor < ActiveRecord::Base
94
- has_many :instructor_roles, -> { active }
95
- end
118
+ * Skip calling `PG::Connection#cancel` in `cancel_any_running_query`
119
+ when using libpq >= 18 with pg < 1.6.0, due to incompatibility.
120
+ Rollback still runs, but may take longer.
96
121
 
97
- class InstructorRole < ActiveRecord::Base
98
- scope :active, -> {
99
- joins("JOIN students ON instructor_roles.student_id = students.id")
100
- .where(students { status: 1 })
101
- }
102
- end
122
+ *Yasuo Honda*, *Lars Kanis*
103
123
 
104
- Instructor.joins(:instructor_roles).first
105
- ```
124
+ * Don't add `id_value` attribute alias when attribute/column with that name already exists.
106
125
 
107
- The above example would result in `ActiveRecord::StatementInvalid` because the
108
- `active` scope bind parameters would be lost.
126
+ *Rob Lewis*
109
127
 
110
- *Jean Boussier*
128
+ * Remove deprecated `:unsigned_float` and `:unsigned_decimal` column methods for MySQL.
111
129
 
112
- * Fix a potential race condition with system tests and transactional fixtures.
130
+ *Rafael Mendonça França*
113
131
 
114
- *Sjoerd Lagarde*
132
+ * Remove deprecated `:retries` option for the SQLite3 adapter.
115
133
 
116
- * Fix autosave associations to no longer validated unmodified associated records.
134
+ *Rafael Mendonça França*
117
135
 
118
- Active Record was incorrectly performing validation on associated record that
119
- weren't created nor modified as part of the transaction:
136
+ * Introduce new database configuration options `keepalive`, `max_age`, and
137
+ `min_connections` -- and rename `pool` to `max_connections` to match.
120
138
 
121
- ```ruby
122
- Post.create!(author: User.find(1)) # Fail if user is invalid
123
- ```
139
+ There are no changes to default behavior, but these allow for more specific
140
+ control over pool behavior.
124
141
 
125
- *Jean Boussier*
142
+ *Matthew Draper*, *Chris AtLee*, *Rachael Wright-Munn*
126
143
 
127
- * Remember when a database connection has recently been verified (for
128
- two seconds, by default), to avoid repeated reverifications during a
129
- single request.
144
+ * Move `LIMIT` validation from query generation to when `limit()` is called.
130
145
 
131
- This should recreate a similar rate of verification as in Rails 7.1,
132
- where connections are leased for the duration of a request, and thus
133
- only verified once.
146
+ *Hartley McGuire*, *Shuyang*
134
147
 
135
- *Matthew Draper*
148
+ * Add `ActiveRecord::CheckViolation` error class for check constraint violations.
136
149
 
150
+ *Ryuta Kamizono*
137
151
 
138
- ## Rails 8.0.1 (December 13, 2024) ##
152
+ * Add `ActiveRecord::ExclusionViolation` error class for exclusion constraint violations.
139
153
 
140
- * Fix removing foreign keys with :restrict action for MySQL.
154
+ When an exclusion constraint is violated in PostgreSQL, the error will now be raised
155
+ as `ActiveRecord::ExclusionViolation` instead of the generic `ActiveRecord::StatementInvalid`,
156
+ making it easier to handle these specific constraint violations in application code.
141
157
 
142
- *fatkodima*
158
+ This follows the same pattern as other constraint violation error classes like
159
+ `RecordNotUnique` for unique constraint violations and `InvalidForeignKey` for
160
+ foreign key constraint violations.
143
161
 
144
- * Fix a race condition in `ActiveRecord::Base#method_missing` when lazily defining attributes.
162
+ *Ryuta Kamizono*
145
163
 
146
- If multiple thread were concurrently triggering attribute definition on the same model,
147
- it could result in a `NoMethodError` being raised.
164
+ * Attributes filtered by `filter_attributes` will now also be filtered by `filter_parameters`
165
+ so sensitive information is not leaked.
148
166
 
149
- *Jean Boussier*
167
+ *Jill Klang*
150
168
 
151
- * Fix MySQL default functions getting dropped when changing a column's nullability.
169
+ * Add `connection.current_transaction.isolation` API to check current transaction's isolation level.
152
170
 
153
- *Bastian Bartmann*
171
+ Returns the isolation level if it was explicitly set via the `isolation:` parameter
172
+ or through `ActiveRecord.with_transaction_isolation_level`, otherwise returns `nil`.
173
+ Nested transactions return the parent transaction's isolation level.
154
174
 
155
- * Fix `add_unique_constraint`/`add_check_constraint`/`add_foreign_key` to be revertible when given invalid options.
175
+ ```ruby
176
+ # Returns nil when no transaction
177
+ User.connection.current_transaction.isolation # => nil
156
178
 
157
- *fatkodima*
179
+ # Returns explicitly set isolation level
180
+ User.transaction(isolation: :serializable) do
181
+ User.connection.current_transaction.isolation # => :serializable
182
+ end
158
183
 
159
- * Fix asynchronous destroying of polymorphic `belongs_to` associations.
184
+ # Returns nil when isolation not explicitly set
185
+ User.transaction do
186
+ User.connection.current_transaction.isolation # => nil
187
+ end
160
188
 
161
- *fatkodima*
189
+ # Nested transactions inherit parent's isolation
190
+ User.transaction(isolation: :read_committed) do
191
+ User.transaction do
192
+ User.connection.current_transaction.isolation # => :read_committed
193
+ end
194
+ end
195
+ ```
162
196
 
163
- * Fix `insert_all` to not update existing records.
197
+ *Kir Shatrov*
164
198
 
165
- *fatkodima*
199
+ * Fix `#merge` with `#or` or `#and` and a mixture of attributes and SQL strings resulting in an incorrect query.
166
200
 
167
- * `NOT VALID` constraints should not dump in `create_table`.
201
+ ```ruby
202
+ base = Comment.joins(:post).where(user_id: 1).where("recent = 1")
203
+ puts base.merge(base.where(draft: true).or(Post.where(archived: true))).to_sql
204
+ ```
168
205
 
169
- *Ryuta Kamizono*
206
+ Before:
207
+
208
+ ```SQL
209
+ SELECT "comments".* FROM "comments"
210
+ INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
211
+ WHERE (recent = 1)
212
+ AND (
213
+ "comments"."user_id" = 1
214
+ AND (recent = 1)
215
+ AND "comments"."draft" = 1
216
+ OR "posts"."archived" = 1
217
+ )
218
+ ```
170
219
 
171
- * Fix finding by nil composite primary key association.
220
+ After:
221
+
222
+ ```SQL
223
+ SELECT "comments".* FROM "comments"
224
+ INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
225
+ WHERE "comments"."user_id" = 1
226
+ AND (recent = 1)
227
+ AND (
228
+ "comments"."user_id" = 1
229
+ AND (recent = 1)
230
+ AND "comments"."draft" = 1
231
+ OR "posts"."archived" = 1
232
+ )
233
+ ```
172
234
 
173
- *fatkodima*
235
+ *Joshua Young*
174
236
 
175
- * Properly reset composite primary key configuration when setting a primary key.
237
+ * Make schema dumper to account for `ActiveRecord.dump_schemas` when dumping in `:ruby` format.
176
238
 
177
239
  *fatkodima*
178
240
 
179
- * Fix Mysql2Adapter support for prepared statements
241
+ * Add `:touch` option to `update_column`/`update_columns` methods.
180
242
 
181
- Using prepared statements with MySQL could result in a `NoMethodError` exception.
243
+ ```ruby
244
+ # Will update :updated_at/:updated_on alongside :nice column.
245
+ user.update_column(:nice, true, touch: true)
182
246
 
183
- *Jean Boussier*, *Leo Arnold*, *zzak*
247
+ # Will update :updated_at/:updated_on alongside :last_ip column
248
+ user.update_columns(last_ip: request.remote_ip, touch: true)
249
+ ```
184
250
 
185
- * Fix parsing of SQLite foreign key names when they contain non-ASCII characters
251
+ *Dmitrii Ivliev*
186
252
 
187
- *Zacharias Knudsen*
253
+ * Optimize Active Record batching further when using ranges.
188
254
 
189
- * Fix parsing of MySQL 8.0.16+ CHECK constraints when they contain new lines.
255
+ Tested on a PostgreSQL table with 10M records and batches of 10k records, the generation
256
+ of relations for the 1000 batches was `4.8x` faster (`6.8s` vs. `1.4s`), used `900x`
257
+ less bandwidth (`180MB` vs. `0.2MB`) and allocated `45x` less memory (`490MB` vs. `11MB`).
190
258
 
191
- *Steve Hill*
259
+ *Maxime Réty*, *fatkodima*
192
260
 
193
- * Ensure normalized attribute queries use `IS NULL` consistently for `nil` and normalized `nil` values.
261
+ * Include current character length in error messages for index and table name length validations.
194
262
 
195
263
  *Joshua Young*
196
264
 
197
- * Fix `sum` when performing a grouped calculation.
265
+ * Add `rename_schema` method for PostgreSQL.
198
266
 
199
- `User.group(:friendly).sum` no longer worked. This is fixed.
267
+ *T S Vallender*
200
268
 
201
- *Edouard Chin*
269
+ * Implement support for deprecating associations:
202
270
 
203
- * Restore back the ability to pass only database name to `DATABASE_URL`.
271
+ ```ruby
272
+ has_many :posts, deprecated: true
273
+ ```
204
274
 
205
- *fatkodima*
275
+ With that, Active Record will report any usage of the `posts` association.
206
276
 
277
+ Three reporting modes are supported (`:warn`, `:raise`, and `:notify`), and
278
+ backtraces can be enabled or disabled. Defaults are `:warn` mode and
279
+ disabled backtraces.
207
280
 
208
- ## Rails 8.0.0.1 (December 10, 2024) ##
281
+ Please, check the docs for further details.
209
282
 
210
- * No changes.
283
+ *Xavier Noria*
211
284
 
285
+ * PostgreSQL adapter create DB now supports `locale_provider` and `locale`.
212
286
 
213
- ## Rails 8.0.0 (November 07, 2024) ##
287
+ *Bengt-Ove Hollaender*
214
288
 
215
- * Fix support for `query_cache: false` in `database.yml`.
289
+ * Use ntuples to populate row_count instead of count for Postgres
216
290
 
217
- `query_cache: false` would no longer entirely disable the Active Record query cache.
291
+ *Jonathan Calvert*
218
292
 
219
- *zzak*
293
+ * Fix checking whether an unpersisted record is `include?`d in a strictly
294
+ loaded `has_and_belongs_to_many` association.
220
295
 
296
+ *Hartley McGuire*
221
297
 
222
- ## Rails 8.0.0.rc2 (October 30, 2024) ##
298
+ * Add ability to change transaction isolation for all pools within a block.
223
299
 
224
- * NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
300
+ This functionality is useful if your application needs to change the database
301
+ transaction isolation for a request or action.
225
302
 
226
- *Ryuta Kamizono*
303
+ Calling `ActiveRecord.with_transaction_isolation_level(level) {}` in an around filter or
304
+ middleware will set the transaction isolation for all pools accessed within the block,
305
+ but not for the pools that aren't.
227
306
 
228
- * The `db:prepare` task no longer loads seeds when a non-primary database is created.
307
+ This works with explicit and implicit transactions:
229
308
 
230
- Previously, the `db:prepare` task would load seeds whenever a new database
231
- is created, leading to potential loss of data if a database is added to an
232
- existing environment.
309
+ ```ruby
310
+ ActiveRecord.with_transaction_isolation_level(:read_committed) do
311
+ Tag.transaction do # opens a transaction explicitly
312
+ Tag.create!
313
+ end
314
+ end
315
+ ```
233
316
 
234
- Introduces a new database config property `seeds` to control whether seeds
235
- are loaded during `db:prepare` which defaults to `true` for primary database
236
- configs and `false` otherwise.
317
+ ```ruby
318
+ ActiveRecord.with_transaction_isolation_level(:read_committed) do
319
+ Tag.create! # opens a transaction implicitly
320
+ end
321
+ ```
237
322
 
238
- Fixes #53348.
323
+ *Eileen M. Uchitelle*
239
324
 
240
- *Mike Dalessio*
325
+ * Raise `ActiveRecord::MissingRequiredOrderError` when order dependent finder methods (e.g. `#first`, `#last`) are
326
+ called without `order` values on the relation, and the model does not have any order columns (`implicit_order_column`,
327
+ `query_constraints`, or `primary_key`) to fall back on.
241
328
 
242
- * `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
329
+ This change will be introduced with a new framework default for Rails 8.1, and the current behavior of not raising
330
+ an error has been deprecated with the aim of removing the configuration option in Rails 8.2.
243
331
 
244
- *Kazuma Watanabe*
332
+ ```ruby
333
+ config.active_record.raise_on_missing_required_finder_order_columns = true
334
+ ```
245
335
 
246
- * Fix strict loading propagation even if statement cache is not used.
336
+ *Joshua Young*
247
337
 
248
- *Ryuta Kamizono*
338
+ * `:class_name` is now invalid in polymorphic `belongs_to` associations.
249
339
 
250
- * Allow `rename_enum` accepts two from/to name arguments as `rename_table` does so.
340
+ Reason is `:class_name` does not make sense in those associations because
341
+ the class name of target records is dynamic and stored in the type column.
251
342
 
252
- *Ryuta Kamizono*
343
+ Existing polymorphic associations setting this option can just delete it.
344
+ While it did not raise, it had no effect anyway.
253
345
 
346
+ *Xavier Noria*
254
347
 
255
- ## Rails 8.0.0.rc1 (October 19, 2024) ##
348
+ * Add support for multiple databases to `db:migrate:reset`.
256
349
 
257
- * Remove deprecated support to setting `ENV["SCHEMA_CACHE"]`.
350
+ *Joé Dupuis*
258
351
 
259
- *Rafael Mendonça França*
352
+ * Add `affected_rows` to `ActiveRecord::Result`.
260
353
 
261
- * Remove deprecated support to passing a database name to `cache_dump_filename`.
354
+ *Jenny Shen*
262
355
 
263
- *Rafael Mendonça França*
356
+ * Enable passing retryable SqlLiterals to `#where`.
264
357
 
265
- * Remove deprecated `ActiveRecord::ConnectionAdapters::ConnectionPool#connection`.
358
+ *Hartley McGuire*
266
359
 
267
- *Rafael Mendonça França*
360
+ * Set default for primary keys in `insert_all`/`upsert_all`.
268
361
 
269
- * Remove deprecated `config.active_record.sqlite3_deprecated_warning`.
362
+ Previously in Postgres, updating and inserting new records in one upsert wasn't possible
363
+ due to null primary key values. `nil` primary key values passed into `insert_all`/`upsert_all`
364
+ are now implicitly set to the default insert value specified by adapter.
270
365
 
271
- *Rafael Mendonça França*
366
+ *Jenny Shen*
272
367
 
273
- * Remove deprecated `config.active_record.warn_on_records_fetched_greater_than`.
368
+ * Add a load hook `active_record_database_configurations` for `ActiveRecord::DatabaseConfigurations`
274
369
 
275
- *Rafael Mendonça França*
370
+ *Mike Dalessio*
276
371
 
277
- * Remove deprecated support for defining `enum` with keyword arguments.
372
+ * Use `TRUE` and `FALSE` for SQLite queries with boolean columns.
278
373
 
279
- *Rafael Mendonça França*
374
+ *Hartley McGuire*
280
375
 
281
- * Remove deprecated support to finding database adapters that aren't registered to Active Record.
376
+ * Bump minimum supported SQLite to 3.23.0.
282
377
 
283
- *Rafael Mendonça França*
378
+ *Hartley McGuire*
284
379
 
285
- * Remove deprecated `config.active_record.allow_deprecated_singular_associations_name`.
380
+ * Allow allocated Active Records to lookup associations.
286
381
 
287
- *Rafael Mendonça França*
382
+ Previously, the association cache isn't setup on allocated record objects, so association
383
+ lookups will crash. Test frameworks like mocha use allocate to check for stubbable instance
384
+ methods, which can trigger an association lookup.
288
385
 
289
- * Remove deprecated `config.active_record.commit_transaction_on_non_local_return`.
386
+ *Gannon McGibbon*
290
387
 
291
- *Rafael Mendonça França*
388
+ * Encryption now supports `support_unencrypted_data: true` being set per-attribute.
292
389
 
293
- * Fix incorrect SQL query when passing an empty hash to `ActiveRecord::Base.insert`.
390
+ Previously this only worked if `ActiveRecord::Encryption.config.support_unencrypted_data == true`.
391
+ Now, if the global config is turned off, you can still opt in for a specific attribute.
294
392
 
295
- *David Stosik*
393
+ ```ruby
394
+ # ActiveRecord::Encryption.config.support_unencrypted_data = true
395
+ class User < ActiveRecord::Base
396
+ encrypts :name, support_unencrypted_data: false # only supports encrypted data
397
+ encrypts :email # supports encrypted or unencrypted data
398
+ end
399
+ ```
296
400
 
297
- * Allow to save records with polymorphic join tables that have `inverse_of`
298
- specified.
401
+ ```ruby
402
+ # ActiveRecord::Encryption.config.support_unencrypted_data = false
403
+ class User < ActiveRecord::Base
404
+ encrypts :name, support_unencrypted_data: true # supports encrypted or unencrypted data
405
+ encrypts :email # only supports encrypted data
406
+ end
407
+ ```
299
408
 
300
- *Markus Doits*
409
+ *Alex Ghiculescu*
301
410
 
302
- * Fix association scopes applying on the incorrect join when using a polymorphic `has_many through:`.
411
+ * Model generator no longer needs a database connection to validate column types.
303
412
 
304
- *Joshua Young*
413
+ *Mike Dalessio*
305
414
 
306
- * Allow `ActiveRecord::Base#pluck` to accept hash arguments with symbol and string values.
415
+ * Allow signed ID verifiers to be configurable via `Rails.application.message_verifiers`
307
416
 
308
- ```ruby
309
- Post.joins(:comments).pluck(:id, comments: :id)
310
- Post.joins(:comments).pluck("id", "comments" => "id")
311
- ```
417
+ Prior to this change, the primary way to configure signed ID verifiers was
418
+ to set `signed_id_verifier` on each model class:
312
419
 
313
- *Joshua Young*
420
+ ```ruby
421
+ Post.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
422
+ Comment.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
423
+ ```
314
424
 
315
- * Make Float distinguish between `float4` and `float8` in PostgreSQL.
425
+ And if the developer did not set `signed_id_verifier`, a verifier would be
426
+ instantiated with a secret derived from `secret_key_base` and the following
427
+ options:
316
428
 
317
- Fixes #52742
429
+ ```ruby
430
+ { digest: "SHA256", serializer: JSON, url_safe: true }
431
+ ```
318
432
 
319
- *Ryota Kitazawa*, *Takayuki Nagatomi*
433
+ Thus it was cumbersome to rotate configuration for all verifiers.
320
434
 
435
+ This change defines a new Rails config: [`config.active_record.use_legacy_signed_id_verifier`][].
436
+ The default value is `:generate_and_verify`, which preserves the previous
437
+ behavior. However, when set to `:verify`, signed ID verifiers will use
438
+ configuration from `Rails.application.message_verifiers` (specifically,
439
+ `Rails.application.message_verifiers["active_record/signed_id"]`) to
440
+ generate and verify signed IDs, but will also verify signed IDs using the
441
+ older configuration.
321
442
 
322
- ## Rails 8.0.0.beta1 (September 26, 2024) ##
443
+ To avoid complication, the new behavior only applies when `signed_id_verifier_secret`
444
+ is not set on a model class or any of its ancestors. Additionally,
445
+ `signed_id_verifier_secret` is now deprecated. If you are currently setting
446
+ `signed_id_verifier_secret` on a model class, you can set `signed_id_verifier`
447
+ instead:
323
448
 
324
- * Allow `drop_table` to accept an array of table names.
449
+ ```ruby
450
+ # BEFORE
451
+ Post.signed_id_verifier_secret = "my secret"
325
452
 
326
- This will let you to drop multiple tables in a single call.
453
+ # AFTER
454
+ Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("my secret", digest: "SHA256", serializer: JSON, url_safe: true)
455
+ ```
327
456
 
328
- ```ruby
329
- ActiveRecord::Base.lease_connection.drop_table(:users, :posts)
330
- ```
457
+ To ease migration, `signed_id_verifier` has also been changed to behave as a
458
+ `class_attribute` (i.e. inheritable), but _only when `signed_id_verifier_secret`
459
+ is not set_:
331
460
 
332
- *Gabriel Sobrinho*
461
+ ```ruby
462
+ # BEFORE
463
+ ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
464
+ Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
333
465
 
334
- * Add support for PostgreSQL `IF NOT EXISTS` via the `:if_not_exists` option
335
- on the `add_enum_value` method.
466
+ # AFTER
467
+ ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
468
+ Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => true
336
469
 
337
- *Ariel Rzezak*
470
+ Post.signed_id_verifier_secret = "my secret" # => deprecation warning
471
+ Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
472
+ ```
338
473
 
339
- * When running `db:migrate` on a fresh database, load the databases schemas before running migrations.
474
+ Note, however, that it is recommended to eventually migrate from
475
+ model-specific verifiers to a unified configuration managed by
476
+ `Rails.application.message_verifiers`. `ActiveSupport::MessageVerifier#rotate`
477
+ can facilitate that transition. For example:
340
478
 
341
- *Andrew Novoselac*, *Marek Kasztelnik*
479
+ ```ruby
480
+ # BEFORE
481
+ # Generate and verify signed Post IDs using Post-specific configuration
482
+ Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("post secret", ...)
342
483
 
343
- * Fix an issue where `.left_outer_joins` used with multiple associations that have
344
- the same child association but different parents does not join all parents.
484
+ # AFTER
485
+ # Generate and verify signed Post IDs using the unified configuration
486
+ Post.signed_id_verifier = Post.signed_id_verifier.dup
487
+ # Fall back to Post-specific configuration when verifying signed IDs
488
+ Post.signed_id_verifier.rotate("post secret", ...)
489
+ ```
345
490
 
346
- Previously, using `.left_outer_joins` with the same child association would only join one of the parents.
491
+ [`config.active_record.use_legacy_signed_id_verifier`]: https://guides.rubyonrails.org/v8.1/configuring.html#config-active-record-use-legacy-signed-id-verifier
347
492
 
348
- Now it will correctly join both parents.
493
+ *Ali Sepehri*, *Jonathan Hefner*
349
494
 
350
- Fixes #41498.
495
+ * Prepend `extra_flags` in postgres' `structure_load`
351
496
 
352
- *Garrett Blehm*
497
+ When specifying `structure_load_flags` with a postgres adapter, the flags
498
+ were appended to the default flags, instead of prepended.
499
+ This caused issues with flags not being taken into account by postgres.
353
500
 
354
- * Deprecate `unsigned_float` and `unsigned_decimal` short-hand column methods.
501
+ *Alice Loeser*
355
502
 
356
- As of MySQL 8.0.17, the UNSIGNED attribute is deprecated for columns of type FLOAT, DOUBLE,
357
- and DECIMAL. Consider using a simple CHECK constraint instead for such columns.
503
+ * Allow bypassing primary key/constraint addition in `implicit_order_column`
358
504
 
359
- https://dev.mysql.com/doc/refman/8.0/en/numeric-type-syntax.html
505
+ When specifying multiple columns in an array for `implicit_order_column`, adding
506
+ `nil` as the last element will prevent appending the primary key to order
507
+ conditions. This allows more precise control of indexes used by
508
+ generated queries. It should be noted that this feature does introduce the risk
509
+ of API misbehavior if the specified columns are not fully unique.
360
510
 
361
- *Ryuta Kamizono*
511
+ *Issy Long*
362
512
 
363
- * Drop MySQL 5.5 support.
513
+ * Allow setting the `schema_format` via database configuration.
364
514
 
365
- MySQL 5.5 is the only version that does not support datetime with precision,
366
- which we have supported in the core. Now we support MySQL 5.6.4 or later, which
367
- is the first version to support datetime with precision.
368
-
369
- *Ryuta Kamizono*
515
+ ```
516
+ primary:
517
+ schema_format: ruby
518
+ ```
370
519
 
371
- * Make Active Record asynchronous queries compatible with transactional fixtures.
520
+ Useful for multi-database setups when apps require different formats per-database.
372
521
 
373
- Previously transactional fixtures would disable asynchronous queries, because transactional
374
- fixtures impose all queries use the same connection.
522
+ *T S Vallender*
375
523
 
376
- Now asynchronous queries will use the connection pinned by transactional fixtures, and behave
377
- much closer to production.
524
+ * Support disabling indexes for MySQL v8.0.0+ and MariaDB v10.6.0+
378
525
 
379
- *Jean Boussier*
526
+ MySQL 8.0.0 added an option to disable indexes from being used by the query
527
+ optimizer by making them "invisible". This allows the index to still be maintained
528
+ and updated but no queries will be permitted to use it. This can be useful for adding
529
+ new invisible indexes or making existing indexes invisible before dropping them
530
+ to ensure queries are not negatively affected.
531
+ See https://dev.mysql.com/blog-archive/mysql-8-0-invisible-indexes/ for more details.
380
532
 
381
- * Deserialize binary data before decrypting
533
+ MariaDB 10.6.0 also added support for this feature by allowing indexes to be "ignored"
534
+ in queries. See https://mariadb.com/kb/en/ignored-indexes/ for more details.
382
535
 
383
- This ensures that we call `PG::Connection.unescape_bytea` on PostgreSQL before decryption.
536
+ Active Record now supports this option for MySQL 8.0.0+ and MariaDB 10.6.0+ for
537
+ index creation and alteration where the new index option `enabled: true/false` can be
538
+ passed to column and index methods as below:
384
539
 
385
- *Donal McBreen*
540
+ ```ruby
541
+ add_index :users, :email, enabled: false
542
+ enable_index :users, :email
543
+ add_column :users, :dob, :string, index: { enabled: false }
544
+
545
+ change_table :users do |t|
546
+ t.index :name, enabled: false
547
+ t.index :dob
548
+ t.disable_index :dob
549
+ t.column :username, :string, index: { enabled: false }
550
+ t.references :account, index: { enabled: false }
551
+ end
386
552
 
387
- * Ensure `ActiveRecord::Encryption.config` is always ready before access.
553
+ create_table :users do |t|
554
+ t.string :name, index: { enabled: false }
555
+ t.string :email
556
+ t.index :email, enabled: false
557
+ end
558
+ ```
388
559
 
389
- Previously, `ActiveRecord::Encryption` configuration was deferred until `ActiveRecord::Base`
390
- was loaded. Therefore, accessing `ActiveRecord::Encryption.config` properties before
391
- `ActiveRecord::Base` was loaded would give incorrect results.
560
+ *Merve Taner*
392
561
 
393
- `ActiveRecord::Encryption` now has its own loading hook so that its configuration is set as
394
- soon as needed.
562
+ * Respect `implicit_order_column` in `ActiveRecord::Relation#reverse_order`.
395
563
 
396
- When `ActiveRecord::Base` is loaded, even lazily, it in turn triggers the loading of
397
- `ActiveRecord::Encryption`, thus preserving the original behavior of having its config ready
398
- before any use of `ActiveRecord::Base`.
564
+ *Joshua Young*
399
565
 
400
- *Maxime Réty*
566
+ * Add column types to `ActiveRecord::Result` for SQLite3.
401
567
 
402
- * Add `TimeZoneConverter#==` method, so objects will be properly compared by
403
- their type, scale, limit & precision.
568
+ *Andrew Kane*
404
569
 
405
- Address #52699.
570
+ * Raise `ActiveRecord::ReadOnlyError` when pessimistically locking with a readonly role.
406
571
 
407
- *Ruy Rocha*
572
+ *Joshua Young*
408
573
 
409
- * Add support for SQLite3 full-text-search and other virtual tables.
574
+ * Fix using the `SQLite3Adapter`'s `dbconsole` method outside of a Rails application.
410
575
 
411
- Previously, adding sqlite3 virtual tables messed up `schema.rb`.
576
+ *Hartley McGuire*
412
577
 
413
- Now, virtual tables can safely be added using `create_virtual_table`.
578
+ * Fix migrating multiple databases with `ActiveRecord::PendingMigration` action.
414
579
 
415
- *Zacharias Knudsen*
580
+ *Gannon McGibbon*
416
581
 
417
- * Support use of alternative database interfaces via the `database_cli` ActiveRecord configuration option.
582
+ * Enable automatically retrying idempotent association queries on connection
583
+ errors.
418
584
 
419
- ```ruby
420
- Rails.application.configure do
421
- config.active_record.database_cli = { postgresql: "pgcli" }
422
- end
423
- ```
585
+ *Hartley McGuire*
424
586
 
425
- *T S Vallender*
587
+ * Add `allow_retry` to `sql.active_record` instrumentation.
426
588
 
427
- * Add support for dumping table inheritance and native partitioning table definitions for PostgeSQL adapter
589
+ This enables identifying queries which queries are automatically retryable on connection errors.
428
590
 
429
- *Justin Talbott*
591
+ *Hartley McGuire*
430
592
 
431
- * Add support for `ActiveRecord::Point` type casts using `Hash` values
593
+ * Better support UPDATE with JOIN for Postgresql and SQLite3
432
594
 
433
- This allows `ActiveRecord::Point` to be cast or serialized from a hash
434
- with `:x` and `:y` keys of numeric values, mirroring the functionality of
435
- existing casts for string and array values. Both string and symbol keys are
436
- supported.
595
+ Previously when generating update queries with one or more JOIN clauses,
596
+ Active Record would use a sub query which would prevent to reference the joined
597
+ tables in the `SET` clause, for instance:
437
598
 
438
599
  ```ruby
439
- class PostgresqlPoint < ActiveRecord::Base
440
- attribute :x, :point
441
- attribute :y, :point
442
- attribute :z, :point
443
- end
444
-
445
- val = PostgresqlPoint.new({
446
- x: '(12.34, -43.21)',
447
- y: [12.34, '-43.21'],
448
- z: {x: '12.34', y: -43.21}
449
- })
450
- ActiveRecord::Point.new(12.32, -43.21) == val.x == val.y == val.z
600
+ Comment.joins(:post).update_all("title = posts.title")
451
601
  ```
452
602
 
453
- *Stephen Drew*
603
+ This is now supported as long as the relation doesn't also use a `LIMIT`, `ORDER` or
604
+ `GROUP BY` clause. This was supported by the MySQL adapter for a long time.
454
605
 
455
- * Replace `SQLite3::Database#busy_timeout` with `#busy_handler_timeout=`.
606
+ *Jean Boussier*
456
607
 
457
- Provides a non-GVL-blocking, fair retry interval busy handler implementation.
608
+ * Introduce a before-fork hook in `ActiveSupport::Testing::Parallelization` to clear existing
609
+ connections, to avoid fork-safety issues with the mysql2 adapter.
458
610
 
459
- *Stephen Margheim*
611
+ Fixes #41776
460
612
 
461
- * SQLite3Adapter: Translate `SQLite3::BusyException` into `ActiveRecord::StatementTimeout`.
613
+ *Mike Dalessio*, *Donal McBreen*
462
614
 
463
- *Matthew Nguyen*
615
+ * PoolConfig no longer keeps a reference to the connection class.
464
616
 
465
- * Include schema name in `enable_extension` statements in `db/schema.rb`.
617
+ Keeping a reference to the class caused subtle issues when combined with reloading in
618
+ development. Fixes #54343.
466
619
 
467
- The schema dumper will now include the schema name in generated
468
- `enable_extension` statements if they differ from the current schema.
620
+ *Mike Dalessio*
469
621
 
470
- For example, if you have a migration:
622
+ * Fix SQL notifications sometimes not sent when using async queries.
471
623
 
472
624
  ```ruby
473
- enable_extension "heroku_ext.pgcrypto"
474
- enable_extension "pg_stat_statements"
625
+ Post.async_count
626
+ ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) do
627
+ Post.count
628
+ end
475
629
  ```
476
630
 
477
- then the generated schema dump will also contain:
631
+ In rare circumstances and under the right race condition, Active Support notifications
632
+ would no longer be dispatched after using an asynchronous query.
633
+ This is now fixed.
478
634
 
479
- ```ruby
480
- enable_extension "heroku_ext.pgcrypto"
481
- enable_extension "pg_stat_statements"
482
- ```
635
+ *Edouard Chin*
483
636
 
484
- *Tony Novak*
637
+ * Eliminate queries loading dumped schema cache on Postgres
485
638
 
486
- * Fix `ActiveRecord::Encryption::EncryptedAttributeType#type` to return
487
- actual cast type.
639
+ Improve resiliency by avoiding needing to open a database connection to load the
640
+ type map while defining attribute methods at boot when a schema cache file is
641
+ configured on PostgreSQL databases.
488
642
 
489
- *Vasiliy Ermolovich*
643
+ *James Coleman*
490
644
 
491
- * SQLite3Adapter: Bulk insert fixtures.
645
+ * `ActiveRecord::Coder::JSON` can be instantiated
492
646
 
493
- Previously one insert command was executed for each fixture, now they are
494
- aggregated in a single bulk insert command.
647
+ Options can now be passed to `ActiveRecord::Coder::JSON` when instantiating the coder. This allows:
648
+ ```ruby
649
+ serialize :config, coder: ActiveRecord::Coder::JSON.new(symbolize_names: true)
650
+ ```
651
+ *matthaigh27*
495
652
 
496
- *Lázaro Nixon*
653
+ * Deprecate using `insert_all`/`upsert_all` with unpersisted records in associations.
497
654
 
498
- * PostgreSQLAdapter: Allow `disable_extension` to be called with schema-qualified name.
655
+ Using these methods on associations containing unpersisted records will now
656
+ show a deprecation warning, as the unpersisted records will be lost after
657
+ the operation.
499
658
 
500
- For parity with `enable_extension`, the `disable_extension` method can be called with a schema-qualified
501
- name (e.g. `disable_extension "myschema.pgcrypto"`). Note that PostgreSQL's `DROP EXTENSION` does not
502
- actually take a schema name (unlike `CREATE EXTENSION`), so the resulting SQL statement will only name
503
- the extension, e.g. `DROP EXTENSION IF EXISTS "pgcrypto"`.
659
+ *Nick Schwaderer*
504
660
 
505
- *Tony Novak*
661
+ * Make column name optional for `index_exists?`.
506
662
 
507
- * Make `create_schema` / `drop_schema` reversible in migrations.
663
+ This aligns well with `remove_index` signature as well, where
664
+ index name doesn't need to be derived from the column names.
508
665
 
509
- Previously, `create_schema` and `drop_schema` were irreversible migration operations.
666
+ *Ali Ismayiliov*
510
667
 
511
- *Tony Novak*
668
+ * Change the payload name of `sql.active_record` notification for eager
669
+ loading from "SQL" to "#{model.name} Eager Load".
512
670
 
513
- * Support batching using custom columns.
671
+ *zzak*
514
672
 
515
- ```ruby
516
- Product.in_batches(cursor: [:shop_id, :id]) do |relation|
517
- # do something with relation
518
- end
519
- ```
673
+ * Enable automatically retrying idempotent `#exists?` queries on connection
674
+ errors.
520
675
 
521
- *fatkodima*
676
+ *Hartley McGuire*, *classidied*
522
677
 
523
- * Use SQLite `IMMEDIATE` transactions when possible.
678
+ * Deprecate usage of unsupported methods in conjunction with `update_all`:
524
679
 
525
- Transactions run against the SQLite3 adapter default to IMMEDIATE mode to improve concurrency support and avoid busy exceptions.
680
+ `update_all` will now print a deprecation message if a query includes either `WITH`,
681
+ `WITH RECURSIVE` or `DISTINCT` statements. Those were never supported and were ignored
682
+ when generating the SQL query.
526
683
 
527
- *Stephen Margheim*
684
+ An error will be raised in a future Rails release. This behavior will be consistent
685
+ with `delete_all` which currently raises an error for unsupported statements.
528
686
 
529
- * Raise specific exception when a connection is not defined.
687
+ *Edouard Chin*
530
688
 
531
- The new `ConnectionNotDefined` exception provides connection name, shard and role accessors indicating the details of the connection that was requested.
689
+ * The table columns inside `schema.rb` are now sorted alphabetically.
532
690
 
533
- *Hana Harencarova*, *Matthew Draper*
691
+ Previously they'd be sorted by creation order, which can cause merge conflicts when two
692
+ branches modify the same table concurrently.
534
693
 
535
- * Delete the deprecated constant `ActiveRecord::ImmutableRelation`.
694
+ *John Duff*
536
695
 
537
- *Xavier Noria*
696
+ * Introduce versions formatter for the schema dumper.
538
697
 
539
- * Fix duplicate callback execution when child autosaves parent with `has_one` and `belongs_to`.
698
+ It is now possible to override how schema dumper formats versions information inside the
699
+ `structure.sql` file. Currently, the versions are simply sorted in the decreasing order.
700
+ Within large teams, this can potentially cause many merge conflicts near the top of the list.
540
701
 
541
- Before, persisting a new child record with a new associated parent record would run `before_validation`,
542
- `after_validation`, `before_save` and `after_save` callbacks twice.
702
+ Now, the custom formatter can be provided with a custom sorting logic (e.g. by hash values
703
+ of the versions), which can greatly reduce the number of conflicts.
543
704
 
544
- Now, these callbacks are only executed once as expected.
705
+ *fatkodima*
545
706
 
546
- *Joshua Young*
707
+ * Serialized attributes can now be marked as comparable.
547
708
 
548
- * `ActiveRecord::Encryption::Encryptor` now supports a `:compressor` option to customize the compression algorithm used.
709
+ A not rare issue when working with serialized attributes is that the serialized representation of an object
710
+ can change over time. Either because you are migrating from one serializer to the other (e.g. YAML to JSON or to msgpack),
711
+ or because the serializer used subtly changed its output.
549
712
 
550
- ```ruby
551
- module ZstdCompressor
552
- def self.deflate(data)
553
- Zstd.compress(data)
554
- end
713
+ One example is libyaml that used to have some extra trailing whitespaces, and recently fixed that.
714
+ When this sorts of thing happen, you end up with lots of records that report being changed even though
715
+ they aren't, which in the best case leads to a lot more writes to the database and in the worst case lead to nasty bugs.
555
716
 
556
- def self.inflate(data)
557
- Zstd.decompress(data)
558
- end
559
- end
717
+ The solution is to instead compare the deserialized representation of the object, however Active Record
718
+ can't assume the deserialized object has a working `==` method. Hence why this new functionality is opt-in.
560
719
 
561
- class User
562
- encrypts :name, compressor: ZstdCompressor
563
- end
720
+ ```ruby
721
+ serialize :config, type: Hash, coder: JSON, comparable: true
564
722
  ```
565
723
 
566
- You disable compression by passing `compress: false`.
724
+ *Jean Boussier*
567
725
 
568
- ```ruby
569
- class User
570
- encrypts :name, compress: false
571
- end
572
- ```
726
+ * Fix MySQL default functions getting dropped when changing a column's nullability.
573
727
 
574
- *heka1024*
728
+ *Bastian Bartmann*
575
729
 
576
- * Add condensed `#inspect` for `ConnectionPool`, `AbstractAdapter`, and
577
- `DatabaseConfig`.
730
+ * SQLite extensions can be configured in `config/database.yml`.
578
731
 
579
- *Hartley McGuire*
732
+ The database configuration option `extensions:` allows an application to load SQLite extensions
733
+ when using `sqlite3` >= v2.4.0. The array members may be filesystem paths or the names of
734
+ modules that respond to `.to_path`:
580
735
 
581
- * Add `.shard_keys`, `.sharded?`, & `.connected_to_all_shards` methods.
736
+ ``` yaml
737
+ development:
738
+ adapter: sqlite3
739
+ extensions:
740
+ - SQLean::UUID # module name responding to `.to_path`
741
+ - .sqlpkg/nalgeon/crypto/crypto.so # or a filesystem path
742
+ - <%= AppExtensions.location %> # or ruby code returning a path
743
+ ```
582
744
 
583
- ```ruby
584
- class ShardedBase < ActiveRecord::Base
585
- self.abstract_class = true
745
+ *Mike Dalessio*
586
746
 
587
- connects_to shards: {
588
- shard_one: { writing: :shard_one },
589
- shard_two: { writing: :shard_two }
590
- }
591
- end
747
+ * `ActiveRecord::Middleware::ShardSelector` supports granular database connection switching.
592
748
 
593
- class ShardedModel < ShardedBase
594
- end
749
+ A new configuration option, `class_name:`, is introduced to
750
+ `config.active_record.shard_selector` to allow an application to specify the abstract connection
751
+ class to be switched by the shard selection middleware. The default class is
752
+ `ActiveRecord::Base`.
753
+
754
+ For example, this configuration tells `ShardSelector` to switch shards using
755
+ `AnimalsRecord.connected_to`:
595
756
 
596
- ShardedModel.shard_keys => [:shard_one, :shard_two]
597
- ShardedModel.sharded? => true
598
- ShardedBase.connected_to_all_shards { ShardedModel.current_shard } => [:shard_one, :shard_two]
757
+ ```
758
+ config.active_record.shard_selector = { class_name: "AnimalsRecord" }
599
759
  ```
600
760
 
601
- *Nony Dutton*
761
+ *Mike Dalessio*
602
762
 
603
- * Add a `filter` option to `in_order_of` to prioritize certain values in the sorting without filtering the results
604
- by these values.
763
+ * Reset relations after `insert_all`/`upsert_all`.
605
764
 
606
- *Igor Depolli*
765
+ Bulk insert/upsert methods will now call `reset` if used on a relation, matching the behavior of `update_all`.
607
766
 
608
- * Fix an issue where the IDs reader method did not return expected results
609
- for preloaded associations in models using composite primary keys.
767
+ *Milo Winningham*
610
768
 
611
- *Jay Ang*
769
+ * Use `_N` as a parallel tests databases suffixes
612
770
 
613
- * Allow to configure `strict_loading_mode` globally or within a model.
771
+ Peviously, `-N` was used as a suffix. This can cause problems for RDBMSes
772
+ which do not support dashes in database names.
614
773
 
615
- Defaults to `:all`, can be changed to `:n_plus_one_only`.
774
+ *fatkodima*
616
775
 
617
- *Garen Torikian*
776
+ * Remember when a database connection has recently been verified (for
777
+ two seconds, by default), to avoid repeated reverifications during a
778
+ single request.
618
779
 
619
- * Add `ActiveRecord::Relation#readonly?`.
780
+ This should recreate a similar rate of verification as in Rails 7.1,
781
+ where connections are leased for the duration of a request, and thus
782
+ only verified once.
620
783
 
621
- Reflects if the relation has been marked as readonly.
784
+ *Matthew Draper*
622
785
 
623
- *Theodor Tonum*
786
+ * Allow to reset cache counters for multiple records.
624
787
 
625
- * Improve `ActiveRecord::Store` to raise a descriptive exception if the column is not either
626
- structured (e.g., PostgreSQL +hstore+/+json+, or MySQL +json+) or declared serializable via
627
- `ActiveRecord.store`.
788
+ ```
789
+ Aircraft.reset_counters([1, 2, 3], :wheels_count)
790
+ ```
628
791
 
629
- Previously, a `NoMethodError` would be raised when the accessor was read or written:
792
+ It produces much fewer queries compared to the custom implementation using looping over ids.
793
+ Previously: `O(ids.size * counters.size)` queries, now: `O(ids.size + counters.size)` queries.
630
794
 
631
- NoMethodError: undefined method `accessor' for an instance of ActiveRecord::Type::Text
795
+ *fatkodima*
632
796
 
633
- Now, a descriptive `ConfigurationError` is raised:
797
+ * Add `affected_rows` to `sql.active_record` Notification.
634
798
 
635
- ActiveRecord::ConfigurationError: the column 'metadata' has not been configured as a store.
636
- Please make sure the column is declared serializable via 'ActiveRecord.store' or, if your
637
- database supports it, use a structured column type like hstore or json.
799
+ *Hartley McGuire*
638
800
 
639
- *Mike Dalessio*
801
+ * Fix `sum` when performing a grouped calculation.
640
802
 
641
- * Fix inference of association model on nested models with the same demodularized name.
803
+ `User.group(:friendly).sum` no longer worked. This is fixed.
804
+
805
+ *Edouard Chin*
806
+
807
+ * Add support for enabling or disabling transactional tests per database.
642
808
 
643
- E.g. with the following setup:
809
+ A test class can now override the default `use_transactional_tests` setting
810
+ for individual databases, which can be useful if some databases need their
811
+ current state to be accessible to an external process while tests are running.
644
812
 
645
813
  ```ruby
646
- class Nested::Post < ApplicationRecord
647
- has_one :post, through: :other
814
+ class MostlyTransactionalTest < ActiveSupport::TestCase
815
+ self.use_transactional_tests = true
816
+ skip_transactional_tests_for_database :shared
648
817
  end
649
818
  ```
650
819
 
651
- Before, `#post` would infer the model as `Nested::Post`, but now it correctly infers `Post`.
820
+ *Matthew Cheetham*, *Morgan Mareve*
652
821
 
653
- *Joshua Young*
822
+ * Cast `query_cache` value when using URL configuration.
823
+
824
+ *zzak*
654
825
 
655
- * Add public method for checking if a table is ignored by the schema cache.
826
+ * NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
656
827
 
657
- Previously, an application would need to reimplement `ignored_table?` from the schema cache class to check if a table was set to be ignored. This adds a public method to support this and updates the schema cache to use that directly.
828
+ *Ryuta Kamizono*
658
829
 
659
- ```ruby
660
- ActiveRecord.schema_cache_ignored_tables = ["developers"]
661
- ActiveRecord.schema_cache_ignored_table?("developers")
662
- => true
663
- ```
830
+ * `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
664
831
 
665
- *Eileen M. Uchitelle*
832
+ *Kazuma Watanabe*
666
833
 
667
- Please check [7-2-stable](https://github.com/rails/rails/blob/7-2-stable/activerecord/CHANGELOG.md) for previous changes.
834
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/activerecord/CHANGELOG.md) for previous changes.