activerecord 8.0.2.1 → 8.1.0.beta1

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