activerecord 8.0.3 → 8.1.1

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