activerecord 7.2.2.1 → 8.1.2

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +564 -753
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/association_relation.rb +2 -1
  5. data/lib/active_record/associations/alias_tracker.rb +6 -4
  6. data/lib/active_record/associations/association.rb +35 -11
  7. data/lib/active_record/associations/belongs_to_association.rb +18 -2
  8. data/lib/active_record/associations/builder/association.rb +23 -11
  9. data/lib/active_record/associations/builder/belongs_to.rb +17 -4
  10. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  11. data/lib/active_record/associations/builder/has_one.rb +1 -1
  12. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  13. data/lib/active_record/associations/collection_association.rb +10 -8
  14. data/lib/active_record/associations/collection_proxy.rb +22 -4
  15. data/lib/active_record/associations/deprecation.rb +88 -0
  16. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  17. data/lib/active_record/associations/errors.rb +3 -0
  18. data/lib/active_record/associations/has_many_through_association.rb +3 -2
  19. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  20. data/lib/active_record/associations/join_dependency.rb +4 -2
  21. data/lib/active_record/associations/preloader/association.rb +2 -2
  22. data/lib/active_record/associations/preloader/batch.rb +7 -1
  23. data/lib/active_record/associations/preloader/branch.rb +1 -0
  24. data/lib/active_record/associations/singular_association.rb +8 -3
  25. data/lib/active_record/associations.rb +192 -24
  26. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  27. data/lib/active_record/attribute_methods/primary_key.rb +4 -8
  28. data/lib/active_record/attribute_methods/query.rb +34 -0
  29. data/lib/active_record/attribute_methods/serialization.rb +17 -4
  30. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
  31. data/lib/active_record/attribute_methods.rb +24 -19
  32. data/lib/active_record/attributes.rb +40 -26
  33. data/lib/active_record/autosave_association.rb +91 -39
  34. data/lib/active_record/base.rb +3 -4
  35. data/lib/active_record/coders/json.rb +14 -5
  36. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
  37. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  38. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
  39. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
  40. data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
  41. data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
  42. data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
  43. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  44. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  45. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  46. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
  47. data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
  48. data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
  49. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
  50. data/lib/active_record/connection_adapters/column.rb +17 -4
  51. data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
  52. data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
  53. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  54. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  55. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
  56. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
  57. data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
  58. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  59. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  60. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  62. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
  65. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  66. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  67. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
  68. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  69. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
  70. data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
  71. data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
  72. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
  73. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
  74. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  75. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
  76. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
  77. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
  78. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  79. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
  80. data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
  81. data/lib/active_record/connection_adapters.rb +1 -56
  82. data/lib/active_record/connection_handling.rb +37 -10
  83. data/lib/active_record/core.rb +61 -25
  84. data/lib/active_record/counter_cache.rb +34 -9
  85. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
  86. data/lib/active_record/database_configurations/database_config.rb +9 -1
  87. data/lib/active_record/database_configurations/hash_config.rb +67 -9
  88. data/lib/active_record/database_configurations/url_config.rb +13 -3
  89. data/lib/active_record/database_configurations.rb +7 -3
  90. data/lib/active_record/delegated_type.rb +19 -19
  91. data/lib/active_record/dynamic_matchers.rb +54 -69
  92. data/lib/active_record/encryption/config.rb +3 -1
  93. data/lib/active_record/encryption/encryptable_record.rb +9 -9
  94. data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
  95. data/lib/active_record/encryption/encryptor.rb +49 -28
  96. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  97. data/lib/active_record/encryption/scheme.rb +9 -2
  98. data/lib/active_record/enum.rb +46 -42
  99. data/lib/active_record/errors.rb +36 -12
  100. data/lib/active_record/explain.rb +1 -1
  101. data/lib/active_record/explain_registry.rb +51 -2
  102. data/lib/active_record/filter_attribute_handler.rb +73 -0
  103. data/lib/active_record/fixture_set/table_row.rb +19 -2
  104. data/lib/active_record/fixtures.rb +2 -4
  105. data/lib/active_record/future_result.rb +13 -9
  106. data/lib/active_record/gem_version.rb +3 -3
  107. data/lib/active_record/inheritance.rb +1 -1
  108. data/lib/active_record/insert_all.rb +12 -7
  109. data/lib/active_record/locking/optimistic.rb +8 -1
  110. data/lib/active_record/locking/pessimistic.rb +5 -0
  111. data/lib/active_record/log_subscriber.rb +3 -13
  112. data/lib/active_record/middleware/shard_selector.rb +34 -17
  113. data/lib/active_record/migration/command_recorder.rb +44 -11
  114. data/lib/active_record/migration/compatibility.rb +37 -24
  115. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  116. data/lib/active_record/migration.rb +50 -43
  117. data/lib/active_record/model_schema.rb +38 -13
  118. data/lib/active_record/nested_attributes.rb +6 -6
  119. data/lib/active_record/persistence.rb +162 -133
  120. data/lib/active_record/query_cache.rb +22 -15
  121. data/lib/active_record/query_logs.rb +104 -52
  122. data/lib/active_record/query_logs_formatter.rb +17 -28
  123. data/lib/active_record/querying.rb +12 -12
  124. data/lib/active_record/railtie.rb +37 -32
  125. data/lib/active_record/railties/controller_runtime.rb +11 -6
  126. data/lib/active_record/railties/databases.rake +26 -37
  127. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  128. data/lib/active_record/railties/job_runtime.rb +10 -11
  129. data/lib/active_record/reflection.rb +53 -21
  130. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  131. data/lib/active_record/relation/batches.rb +147 -73
  132. data/lib/active_record/relation/calculations.rb +80 -63
  133. data/lib/active_record/relation/delegation.rb +25 -15
  134. data/lib/active_record/relation/finder_methods.rb +54 -37
  135. data/lib/active_record/relation/merger.rb +8 -8
  136. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
  137. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  138. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  139. data/lib/active_record/relation/predicate_builder.rb +22 -7
  140. data/lib/active_record/relation/query_attribute.rb +4 -2
  141. data/lib/active_record/relation/query_methods.rb +156 -95
  142. data/lib/active_record/relation/spawn_methods.rb +7 -7
  143. data/lib/active_record/relation/where_clause.rb +10 -11
  144. data/lib/active_record/relation.rb +122 -80
  145. data/lib/active_record/result.rb +109 -24
  146. data/lib/active_record/runtime_registry.rb +42 -58
  147. data/lib/active_record/sanitization.rb +9 -6
  148. data/lib/active_record/schema_dumper.rb +47 -22
  149. data/lib/active_record/schema_migration.rb +2 -1
  150. data/lib/active_record/scoping/named.rb +5 -2
  151. data/lib/active_record/scoping.rb +0 -1
  152. data/lib/active_record/secure_token.rb +3 -3
  153. data/lib/active_record/signed_id.rb +47 -18
  154. data/lib/active_record/statement_cache.rb +24 -20
  155. data/lib/active_record/store.rb +51 -22
  156. data/lib/active_record/structured_event_subscriber.rb +85 -0
  157. data/lib/active_record/table_metadata.rb +6 -23
  158. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  159. data/lib/active_record/tasks/database_tasks.rb +85 -85
  160. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  161. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  162. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
  163. data/lib/active_record/test_databases.rb +14 -4
  164. data/lib/active_record/test_fixtures.rb +39 -2
  165. data/lib/active_record/testing/query_assertions.rb +8 -2
  166. data/lib/active_record/timestamp.rb +4 -2
  167. data/lib/active_record/token_for.rb +1 -1
  168. data/lib/active_record/transaction.rb +2 -5
  169. data/lib/active_record/transactions.rb +39 -16
  170. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  171. data/lib/active_record/type/internal/timezone.rb +7 -0
  172. data/lib/active_record/type/json.rb +15 -2
  173. data/lib/active_record/type/serialized.rb +11 -4
  174. data/lib/active_record/type/type_map.rb +1 -1
  175. data/lib/active_record/type_caster/connection.rb +2 -1
  176. data/lib/active_record/validations/associated.rb +1 -1
  177. data/lib/active_record/validations/uniqueness.rb +8 -8
  178. data/lib/active_record.rb +85 -50
  179. data/lib/arel/alias_predication.rb +2 -0
  180. data/lib/arel/collectors/bind.rb +2 -2
  181. data/lib/arel/collectors/sql_string.rb +1 -1
  182. data/lib/arel/collectors/substitute_binds.rb +2 -2
  183. data/lib/arel/crud.rb +8 -11
  184. data/lib/arel/delete_manager.rb +5 -0
  185. data/lib/arel/nodes/binary.rb +1 -1
  186. data/lib/arel/nodes/count.rb +2 -2
  187. data/lib/arel/nodes/delete_statement.rb +4 -2
  188. data/lib/arel/nodes/function.rb +4 -10
  189. data/lib/arel/nodes/named_function.rb +2 -2
  190. data/lib/arel/nodes/node.rb +2 -2
  191. data/lib/arel/nodes/sql_literal.rb +1 -1
  192. data/lib/arel/nodes/update_statement.rb +4 -2
  193. data/lib/arel/nodes.rb +0 -2
  194. data/lib/arel/select_manager.rb +13 -4
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/update_manager.rb +5 -0
  197. data/lib/arel/visitors/dot.rb +2 -3
  198. data/lib/arel/visitors/postgresql.rb +55 -0
  199. data/lib/arel/visitors/sqlite.rb +55 -8
  200. data/lib/arel/visitors/to_sql.rb +6 -22
  201. data/lib/arel.rb +3 -1
  202. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  203. metadata +17 -17
  204. data/lib/active_record/explain_subscriber.rb +0 -34
  205. data/lib/active_record/normalization.rb +0 -163
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -52
data/CHANGELOG.md CHANGED
@@ -1,1098 +1,909 @@
1
- ## Rails 7.2.2.1 (December 10, 2024) ##
1
+ ## Rails 8.1.2 (January 08, 2026) ##
2
2
 
3
- * No changes.
4
-
5
-
6
- ## Rails 7.2.2 (October 30, 2024) ##
7
-
8
- * Fix support for `query_cache: false` in `database.yml`.
9
-
10
- `query_cache: false` would no longer entirely disable the Active Record query cache.
11
-
12
- *zzak*
13
-
14
- * Set `.attributes_for_inspect` to `:all` by default.
15
-
16
- For new applications it is set to `[:id]` in config/environment/production.rb.
17
-
18
- In the console all the attributes are always shown.
19
-
20
- *Andrew Novoselac*
3
+ * Fix counting cached queries in `ActiveRecord::RuntimeRegistry`.
21
4
 
22
- * `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
23
-
24
- *Kazuma Watanabe*
25
-
26
- * Fix marshalling of unsaved associated records in 7.1 format.
27
-
28
- The 7.1 format would only marshal associated records if the association was loaded.
29
- But associations that would only contain unsaved records would be skipped.
5
+ *fatkodima*
30
6
 
31
- *Jean Boussier*
7
+ * Fix merging relations with arel equality predicates with null relations.
32
8
 
33
- * Fix incorrect SQL query when passing an empty hash to `ActiveRecord::Base.insert`.
9
+ *fatkodima*
34
10
 
35
- *David Stosik*
11
+ * Fix SQLite3 schema dump for non-autoincrement integer primary keys.
36
12
 
37
- * Allow to save records with polymorphic join tables that have `inverse_of`
38
- specified.
13
+ Previously, `schema.rb` should incorrectly restore that table with an auto incrementing
14
+ primary key.
39
15
 
40
- *Markus Doits*
16
+ *Chris Hasiński*
41
17
 
42
- * Fix association scopes applying on the incorrect join when using a polymorphic `has_many through:`.
18
+ * Fix PostgreSQL `schema_search_path` not being reapplied after `reset!` or `reconnect!`.
43
19
 
44
- *Joshua Young*
20
+ The `schema_search_path` configured in `database.yml` is now correctly
21
+ reapplied instead of falling back to PostgreSQL defaults.
45
22
 
46
- * Fix `dependent: :destroy` for bi-directional has one through association.
23
+ *Tobias Egli*
47
24
 
48
- Fixes #50948.
25
+ * Restore the ability of enum to be foats.
49
26
 
50
27
  ```ruby
51
- class Left < ActiveRecord::Base
52
- has_one :middle, dependent: :destroy
53
- has_one :right, through: :middle
54
- end
55
-
56
- class Middle < ActiveRecord::Base
57
- belongs_to :left, dependent: :destroy
58
- belongs_to :right, dependent: :destroy
59
- end
60
-
61
- class Right < ActiveRecord::Base
62
- has_one :middle, dependent: :destroy
63
- has_one :left, through: :middle
64
- end
28
+ enum :rating, { low: 0.0, medium: 0.5, high: 1.0 },
65
29
  ```
66
- In the above example `left.destroy` wouldn't destroy its associated `Right`
67
- record.
68
-
69
- *Andy Stewart*
70
30
 
71
- * Properly handle lazily pinned connection pools.
31
+ In Rails 8.1.0, enum values are eagerly validated, and floats weren't expected.
72
32
 
73
- Fixes #53147.
33
+ *Said Kaldybaev*
74
34
 
75
- When using transactional fixtures with system tests to similar tools
76
- such as capybara, it could happen that a connection end up pinned by the
77
- server thread rather than the test thread, causing
78
- `"Cannot expire connection, it is owned by a different thread"` errors.
35
+ * Ensure batched preloaded associations accounts for klass when grouping to avoid issues with STI.
79
36
 
80
- *Jean Boussier*
37
+ *zzak*, *Stjepan Hadjic*
81
38
 
82
- * Fix `ActiveRecord::Base.with` to accept more than two sub queries.
39
+ * Fix `ActiveRecord::SoleRecordExceeded#record` to return the relation.
83
40
 
84
- Fixes #53110.
41
+ This was the case until Rails 7.2, but starting from 8.0 it
42
+ started mistakenly returning the model class.
85
43
 
86
- ```ruby
87
- User.with(foo: [User.select(:id), User.select(:id), User.select(:id)]).to_sql
88
- undefined method `union' for an instance of Arel::Nodes::UnionAll (NoMethodError)
89
- ```
90
-
91
- The above now works as expected.
44
+ *Jean Boussier*
92
45
 
93
- *fatkodima*
46
+ * Improve PostgreSQLAdapter resilience to Timeout.timeout.
94
47
 
95
- * Properly release pinned connections with non joinable connections.
48
+ Better handle asynchronous exceptions being thrown inside
49
+ the `reconnect!` method.
96
50
 
97
- Fixes #52973
51
+ This may fixes some deep errors such as:
98
52
 
99
- When running system tests with transactional fixtures on, it could happen that
100
- the connection leased by the Puma thread wouldn't be properly released back to the pool,
101
- causing "Cannot expire connection, it is owned by a different thread" errors in later tests.
53
+ ```
54
+ undefined method `key?' for nil:NilClass (NoMethodError)
55
+ if !type_map.key?(oid)
56
+ ```
102
57
 
103
58
  *Jean Boussier*
104
59
 
105
- * Make Float distinguish between `float4` and `float8` in PostgreSQL.
60
+ * Fix structured events for Active Record was not being emitted.
106
61
 
107
- Fixes #52742
62
+ *Yuji Yaginuma*
108
63
 
109
- *Ryota Kitazawa*, *Takayuki Nagatomi*
64
+ * Fix `eager_load` when loading `has_many` assocations with composite primary keys.
110
65
 
111
- * Fix an issue where `.left_outer_joins` used with multiple associations that have
112
- the same child association but different parents does not join all parents.
66
+ This would result in some records being loaded multiple times.
113
67
 
114
- Previously, using `.left_outer_joins` with the same child association would only join one of the parents.
68
+ *Martin-Alexander*
115
69
 
116
- Now it will correctly join both parents.
117
70
 
118
- Fixes #41498.
71
+ ## Rails 8.1.1 (October 28, 2025) ##
119
72
 
120
- *Garrett Blehm*
121
-
122
- * Ensure `ActiveRecord::Encryption.config` is always ready before access.
73
+ * No changes.
123
74
 
124
- Previously, `ActiveRecord::Encryption` configuration was deferred until `ActiveRecord::Base`
125
- was loaded. Therefore, accessing `ActiveRecord::Encryption.config` properties before
126
- `ActiveRecord::Base` was loaded would give incorrect results.
127
75
 
128
- `ActiveRecord::Encryption` now has its own loading hook so that its configuration is set as
129
- soon as needed.
76
+ ## Rails 8.1.0 (October 22, 2025) ##
130
77
 
131
- When `ActiveRecord::Base` is loaded, even lazily, it in turn triggers the loading of
132
- `ActiveRecord::Encryption`, thus preserving the original behavior of having its config ready
133
- before any use of `ActiveRecord::Base`.
78
+ * Fix SQLite3 data loss during table alterations with CASCADE foreign keys.
134
79
 
135
- *Maxime Réty*
80
+ When altering a table in SQLite3 that is referenced by child tables with
81
+ `ON DELETE CASCADE` foreign keys, ActiveRecord would silently delete all
82
+ data from the child tables. This occurred because SQLite requires table
83
+ recreation for schema changes, and during this process the original table
84
+ is temporarily dropped, triggering CASCADE deletes on child tables.
136
85
 
137
- * Add `TimeZoneConverter#==` method, so objects will be properly compared by
138
- their type, scale, limit & precision.
86
+ The root cause was incorrect ordering of operations. The original code
87
+ wrapped `disable_referential_integrity` inside a transaction, but
88
+ `PRAGMA foreign_keys` cannot be modified inside a transaction in SQLite -
89
+ attempting to do so simply has no effect. This meant foreign keys remained
90
+ enabled during table recreation, causing CASCADE deletes to fire.
139
91
 
140
- Address #52699.
92
+ The fix reverses the order to follow the official SQLite 12-step ALTER TABLE
93
+ procedure: `disable_referential_integrity` now wraps the transaction instead
94
+ of being wrapped by it. This ensures foreign keys are properly disabled
95
+ before the transaction starts and re-enabled after it commits, preventing
96
+ CASCADE deletes while maintaining data integrity through atomic transactions.
141
97
 
142
98
  *Ruy Rocha*
143
99
 
100
+ * Add replicas to test database parallelization setup.
144
101
 
145
- ## Rails 7.2.1.2 (October 23, 2024) ##
102
+ Setup and configuration of databases for parallel testing now includes replicas.
146
103
 
147
- * No changes.
104
+ This fixes an issue when using a replica database, database selector middleware,
105
+ and non-transactional tests, where integration tests running in parallel would select
106
+ the base test database, i.e. `db_test`, instead of the numbered parallel worker database,
107
+ i.e. `db_test_{n}`.
148
108
 
109
+ *Adam Maas*
149
110
 
150
- ## Rails 7.2.1.1 (October 15, 2024) ##
111
+ * Support virtual (not persisted) generated columns on PostgreSQL 18+
151
112
 
152
- * No changes.
113
+ PostgreSQL 18 introduces virtual (not persisted) generated columns,
114
+ which are now the default unless the `stored: true` option is explicitly specified on PostgreSQL 18+.
153
115
 
116
+ ```ruby
117
+ create_table :users do |t|
118
+ t.string :name
119
+ t.virtual :lower_name, type: :string, as: "LOWER(name)", stored: false
120
+ t.virtual :name_length, type: :integer, as: "LENGTH(name)"
121
+ end
122
+ ```
154
123
 
155
- ## Rails 7.2.1 (August 22, 2024) ##
124
+ *Yasuo Honda*
156
125
 
157
- * Fix detection for `enum` columns with parallelized tests and PostgreSQL.
126
+ * Optimize schema dumping to prevent duplicate file generation.
158
127
 
159
- *Rafael Mendonça França*
128
+ `ActiveRecord::Tasks::DatabaseTasks.dump_all` now tracks which schema files
129
+ have already been dumped and skips dumping the same file multiple times.
130
+ This improves performance when multiple database configurations share the
131
+ same schema dump path.
160
132
 
161
- * Allow to eager load nested nil associations.
133
+ *Mikey Gough*, *Hartley McGuire*
162
134
 
163
- *fatkodima*
135
+ * Add structured events for Active Record:
136
+ - `active_record.strict_loading_violation`
137
+ - `active_record.sql`
164
138
 
165
- * Fix swallowing ignore order warning when batching using `BatchEnumerator`.
139
+ *Gannon McGibbon*
166
140
 
167
- *fatkodima*
141
+ * Add support for integer shard keys.
142
+ ```ruby
143
+ # Now accepts symbols as shard keys.
144
+ ActiveRecord::Base.connects_to(shards: {
145
+ 1: { writing: :primary_shard_one, reading: :primary_shard_one },
146
+ 2: { writing: :primary_shard_two, reading: :primary_shard_two},
147
+ })
148
+
149
+ ActiveRecord::Base.connected_to(shard: 1) do
150
+ # ..
151
+ end
152
+ ```
168
153
 
169
- * Fix memory bloat on the connection pool when using the Fiber `IsolatedExecutionState`.
154
+ *Nony Dutton*
170
155
 
171
- *Jean Boussier*
156
+ * Add `ActiveRecord::Base.only_columns`
172
157
 
173
- * Restore inferred association class with the same modularized name.
158
+ Similar in use case to `ignored_columns` but listing columns to consider rather than the ones
159
+ to ignore.
174
160
 
175
- *Justin Ko*
161
+ Can be useful when working with a legacy or shared database schema, or to make safe schema change
162
+ in two deploys rather than three.
176
163
 
177
- * Fix `ActiveRecord::Base.inspect` to properly explain how to load schema information.
164
+ *Anton Kandratski*
178
165
 
179
- *Jean Boussier*
166
+ * Use `PG::Connection#close_prepared` (protocol level Close) to deallocate
167
+ prepared statements when available.
180
168
 
181
- * Check invalid `enum` options for the new syntax.
169
+ To enable its use, you must have pg >= 1.6.0, libpq >= 17, and a PostgreSQL
170
+ database version >= 17.
182
171
 
183
- The options using `_` prefix in the old syntax are invalid in the new syntax.
172
+ *Hartley McGuire*, *Andrew Jackson*
184
173
 
185
- *Rafael Mendonça França*
174
+ * Fix query cache for pinned connections in multi threaded transactional tests
186
175
 
187
- * Fix `ActiveRecord::Encryption::EncryptedAttributeType#type` to return
188
- actual cast type.
176
+ When a pinned connection is used across separate threads, they now use a separate cache store
177
+ for each thread.
189
178
 
190
- *Vasiliy Ermolovich*
179
+ This improve accuracy of system tests, and any test using multiple threads.
191
180
 
192
- * Fix `create_table` with `:auto_increment` option for MySQL adapter.
181
+ *Heinrich Lee Yu*, *Jean Boussier*
193
182
 
194
- *fatkodima*
183
+ * Fix time attribute dirty tracking with timezone conversions.
195
184
 
185
+ Time-only attributes now maintain a fixed date of 2000-01-01 during timezone conversions,
186
+ preventing them from being incorrectly marked as changed due to date shifts.
196
187
 
197
- ## Rails 7.2.0 (August 09, 2024) ##
188
+ This fixes an issue where time attributes would be marked as changed when setting the same time value
189
+ due to timezone conversion causing internal date shifts.
198
190
 
199
- * Handle commas in Sqlite3 default function definitions.
191
+ *Prateek Choudhary*
200
192
 
201
- *Stephen Margheim*
193
+ * Skip calling `PG::Connection#cancel` in `cancel_any_running_query`
194
+ when using libpq >= 18 with pg < 1.6.0, due to incompatibility.
195
+ Rollback still runs, but may take longer.
202
196
 
203
- * Fixes `validates_associated` raising an exception when configured with a
204
- singular association and having `index_nested_attribute_errors` enabled.
197
+ *Yasuo Honda*, *Lars Kanis*
205
198
 
206
- *Martin Spickermann*
199
+ * Don't add `id_value` attribute alias when attribute/column with that name already exists.
207
200
 
208
- * The constant `ActiveRecord::ImmutableRelation` has been deprecated because
209
- we want to reserve that name for a stronger sense of "immutable relation".
210
- Please use `ActiveRecord::UnmodifiableRelation` instead.
201
+ *Rob Lewis*
211
202
 
212
- *Xavier Noria*
203
+ * Remove deprecated `:unsigned_float` and `:unsigned_decimal` column methods for MySQL.
213
204
 
214
- * Add condensed `#inspect` for `ConnectionPool`, `AbstractAdapter`, and
215
- `DatabaseConfig`.
205
+ *Rafael Mendonça França*
216
206
 
217
- *Hartley McGuire*
207
+ * Remove deprecated `:retries` option for the SQLite3 adapter.
218
208
 
219
- * Fixed a memory performance issue in Active Record attribute methods definition.
209
+ *Rafael Mendonça França*
220
210
 
221
- *Jean Boussier*
211
+ * Introduce new database configuration options `keepalive`, `max_age`, and
212
+ `min_connections` -- and rename `pool` to `max_connections` to match.
222
213
 
223
- * Define the new Active Support notification event `start_transaction.active_record`.
214
+ There are no changes to default behavior, but these allow for more specific
215
+ control over pool behavior.
224
216
 
225
- This event is fired when database transactions or savepoints start, and
226
- complements `transaction.active_record`, which is emitted when they finish.
217
+ *Matthew Draper*, *Chris AtLee*, *Rachael Wright-Munn*
227
218
 
228
- The payload has the transaction (`:transaction`) and the connection (`:connection`).
219
+ * Move `LIMIT` validation from query generation to when `limit()` is called.
229
220
 
230
- *Xavier Noria*
221
+ *Hartley McGuire*, *Shuyang*
231
222
 
232
- * Fix an issue where the IDs reader method did not return expected results
233
- for preloaded associations in models using composite primary keys.
223
+ * Add `ActiveRecord::CheckViolation` error class for check constraint violations.
234
224
 
235
- *Jay Ang*
225
+ *Ryuta Kamizono*
236
226
 
237
- * The payload of `sql.active_record` Active Support notifications now has the current transaction in the `:transaction` key.
227
+ * Add `ActiveRecord::ExclusionViolation` error class for exclusion constraint violations.
238
228
 
239
- *Xavier Noria*
229
+ When an exclusion constraint is violated in PostgreSQL, the error will now be raised
230
+ as `ActiveRecord::ExclusionViolation` instead of the generic `ActiveRecord::StatementInvalid`,
231
+ making it easier to handle these specific constraint violations in application code.
240
232
 
241
- * The payload of `transaction.active_record` Active Support notifications now has the transaction the event is related to in the `:transaction` key.
233
+ This follows the same pattern as other constraint violation error classes like
234
+ `RecordNotUnique` for unique constraint violations and `InvalidForeignKey` for
235
+ foreign key constraint violations.
242
236
 
243
- *Xavier Noria*
237
+ *Ryuta Kamizono*
244
238
 
245
- * Define `ActiveRecord::Transaction#uuid`, which returns a UUID for the database transaction. This may be helpful when tracing database activity. These UUIDs are generated only on demand.
239
+ * Attributes filtered by `filter_attributes` will now also be filtered by `filter_parameters`
240
+ so sensitive information is not leaked.
246
241
 
247
- *Xavier Noria*
242
+ *Jill Klang*
248
243
 
249
- * Fix inference of association model on nested models with the same demodularized name.
244
+ * Add `connection.current_transaction.isolation` API to check current transaction's isolation level.
250
245
 
251
- E.g. with the following setup:
246
+ Returns the isolation level if it was explicitly set via the `isolation:` parameter
247
+ or through `ActiveRecord.with_transaction_isolation_level`, otherwise returns `nil`.
248
+ Nested transactions return the parent transaction's isolation level.
252
249
 
253
250
  ```ruby
254
- class Nested::Post < ApplicationRecord
255
- has_one :post, through: :other
256
- end
257
- ```
258
-
259
- Before, `#post` would infer the model as `Nested::Post`, but now it correctly infers `Post`.
260
-
261
- *Joshua Young*
262
-
263
- * PostgreSQL `Cidr#change?` detects the address prefix change.
251
+ # Returns nil when no transaction
252
+ User.connection.current_transaction.isolation # => nil
264
253
 
265
- *Taketo Takashima*
254
+ # Returns explicitly set isolation level
255
+ User.transaction(isolation: :serializable) do
256
+ User.connection.current_transaction.isolation # => :serializable
257
+ end
266
258
 
267
- * Change `BatchEnumerator#destroy_all` to return the total number of affected rows.
259
+ # Returns nil when isolation not explicitly set
260
+ User.transaction do
261
+ User.connection.current_transaction.isolation # => nil
262
+ end
268
263
 
269
- Previously, it always returned `nil`.
264
+ # Nested transactions inherit parent's isolation
265
+ User.transaction(isolation: :read_committed) do
266
+ User.transaction do
267
+ User.connection.current_transaction.isolation # => :read_committed
268
+ end
269
+ end
270
+ ```
270
271
 
271
- *fatkodima*
272
+ *Kir Shatrov*
272
273
 
273
- * Support `touch_all` in batches.
274
+ * Fix `#merge` with `#or` or `#and` and a mixture of attributes and SQL strings resulting in an incorrect query.
274
275
 
275
276
  ```ruby
276
- Post.in_batches.touch_all
277
+ base = Comment.joins(:post).where(user_id: 1).where("recent = 1")
278
+ puts base.merge(base.where(draft: true).or(Post.where(archived: true))).to_sql
277
279
  ```
278
280
 
279
- *fatkodima*
280
-
281
- * Add support for `:if_not_exists` and `:force` options to `create_schema`.
282
-
283
- *fatkodima*
284
-
285
- * Fix `index_errors` having incorrect index in association validation errors.
286
-
287
- *lulalala*
288
-
289
- * Add `index_errors: :nested_attributes_order` mode.
290
-
291
- This indexes the association validation errors based on the order received by nested attributes setter, and respects the `reject_if` configuration. This enables API to provide enough information to the frontend to map the validation errors back to their respective form fields.
292
-
293
- *lulalala*
294
-
295
- * Add `Rails.application.config.active_record.postgresql_adapter_decode_dates` to opt out of decoding dates automatically with the postgresql adapter. Defaults to true.
296
-
297
- *Joé Dupuis*
298
-
299
- * Association option `query_constraints` is deprecated in favor of `foreign_key`.
300
-
301
- *Nikita Vasilevsky*
302
-
303
- * Add `ENV["SKIP_TEST_DATABASE_TRUNCATE"]` flag to speed up multi-process test runs on large DBs when all tests run within default transaction.
304
-
305
- This cuts ~10s from the test run of HEY when run by 24 processes against the 178 tables, since ~4,000 table truncates can then be skipped.
306
-
307
- *DHH*
308
-
309
- * Added support for recursive common table expressions.
281
+ Before:
310
282
 
311
- ```ruby
312
- Post.with_recursive(
313
- post_and_replies: [
314
- Post.where(id: 42),
315
- Post.joins('JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id'),
316
- ]
283
+ ```SQL
284
+ SELECT "comments".* FROM "comments"
285
+ INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
286
+ WHERE (recent = 1)
287
+ AND (
288
+ "comments"."user_id" = 1
289
+ AND (recent = 1)
290
+ AND "comments"."draft" = 1
291
+ OR "posts"."archived" = 1
317
292
  )
318
293
  ```
319
294
 
320
- Generates the following SQL:
295
+ After:
321
296
 
322
- ```sql
323
- WITH RECURSIVE "post_and_replies" AS (
324
- (SELECT "posts".* FROM "posts" WHERE "posts"."id" = 42)
325
- UNION ALL
326
- (SELECT "posts".* FROM "posts" JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id)
297
+ ```SQL
298
+ SELECT "comments".* FROM "comments"
299
+ INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
300
+ WHERE "comments"."user_id" = 1
301
+ AND (recent = 1)
302
+ AND (
303
+ "comments"."user_id" = 1
304
+ AND (recent = 1)
305
+ AND "comments"."draft" = 1
306
+ OR "posts"."archived" = 1
327
307
  )
328
- SELECT "posts".* FROM "posts"
329
308
  ```
330
309
 
331
- *ClearlyClaire*
332
-
333
- * `validate_constraint` can be called in a `change_table` block.
310
+ *Joshua Young*
334
311
 
335
- ex:
336
- ```ruby
337
- change_table :products do |t|
338
- t.check_constraint "price > discounted_price", name: "price_check", validate: false
339
- t.validate_check_constraint "price_check"
340
- end
341
- ```
312
+ * Make schema dumper to account for `ActiveRecord.dump_schemas` when dumping in `:ruby` format.
342
313
 
343
- *Cody Cutrer*
314
+ *fatkodima*
344
315
 
345
- * `PostgreSQLAdapter` now decodes columns of type date to `Date` instead of string.
316
+ * Add `:touch` option to `update_column`/`update_columns` methods.
346
317
 
347
- Ex:
348
318
  ```ruby
349
- ActiveRecord::Base.connection
350
- .select_value("select '2024-01-01'::date").class #=> Date
351
- ```
352
-
353
- *Joé Dupuis*
319
+ # Will update :updated_at/:updated_on alongside :nice column.
320
+ user.update_column(:nice, true, touch: true)
354
321
 
355
- * Strict loading using `:n_plus_one_only` does not eagerly load child associations.
322
+ # Will update :updated_at/:updated_on alongside :last_ip column
323
+ user.update_columns(last_ip: request.remote_ip, touch: true)
324
+ ```
356
325
 
357
- With this change, child associations are no longer eagerly loaded, to
358
- match intended behavior and to prevent non-deterministic order issues caused
359
- by calling methods like `first` or `last`. As `first` and `last` don't cause
360
- an N+1 by themselves, calling child associations will no longer raise.
361
- Fixes #49473.
326
+ *Dmitrii Ivliev*
362
327
 
363
- Before:
328
+ * Optimize Active Record batching further when using ranges.
364
329
 
365
- ```ruby
366
- person = Person.find(1)
367
- person.strict_loading!(mode: :n_plus_one_only)
368
- person.posts.first
369
- # SELECT * FROM posts WHERE person_id = 1; -- non-deterministic order
370
- person.posts.first.firm # raises ActiveRecord::StrictLoadingViolationError
371
- ```
330
+ Tested on a PostgreSQL table with 10M records and batches of 10k records, the generation
331
+ of relations for the 1000 batches was `4.8x` faster (`6.8s` vs. `1.4s`), used `900x`
332
+ less bandwidth (`180MB` vs. `0.2MB`) and allocated `45x` less memory (`490MB` vs. `11MB`).
372
333
 
373
- After:
334
+ *Maxime Réty*, *fatkodima*
374
335
 
375
- ```ruby
376
- person = Person.find(1)
377
- person.strict_loading!(mode: :n_plus_one_only)
378
- person.posts.first # this is 1+1, not N+1
379
- # SELECT * FROM posts WHERE person_id = 1 ORDER BY id LIMIT 1;
380
- person.posts.first.firm # no longer raises
381
- ```
336
+ * Include current character length in error messages for index and table name length validations.
382
337
 
383
- *Reid Lynch*
338
+ *Joshua Young*
384
339
 
385
- * Allow `Sqlite3Adapter` to use `sqlite3` gem version `2.x`.
340
+ * Add `rename_schema` method for PostgreSQL.
386
341
 
387
- *Mike Dalessio*
342
+ *T S Vallender*
388
343
 
389
- * Allow `ActiveRecord::Base#pluck` to accept hash values.
344
+ * Implement support for deprecating associations:
390
345
 
391
346
  ```ruby
392
- # Before
393
- Post.joins(:comments).pluck("posts.id", "comments.id", "comments.body")
394
-
395
- # After
396
- Post.joins(:comments).pluck(posts: [:id], comments: [:id, :body])
347
+ has_many :posts, deprecated: true
397
348
  ```
398
349
 
399
- *fatkodima*
350
+ With that, Active Record will report any usage of the `posts` association.
400
351
 
401
- * Raise an `ActiveRecord::ActiveRecordError` error when the MySQL database returns an invalid version string.
352
+ Three reporting modes are supported (`:warn`, `:raise`, and `:notify`), and
353
+ backtraces can be enabled or disabled. Defaults are `:warn` mode and
354
+ disabled backtraces.
402
355
 
403
- *Kevin McPhillips*
356
+ Please, check the docs for further details.
404
357
 
405
- * `ActiveRecord::Base.transaction` now yields an `ActiveRecord::Transaction` object.
358
+ *Xavier Noria*
406
359
 
407
- This allows to register callbacks on it.
360
+ * PostgreSQL adapter create DB now supports `locale_provider` and `locale`.
408
361
 
409
- ```ruby
410
- Article.transaction do |transaction|
411
- article.update(published: true)
412
- transaction.after_commit do
413
- PublishNotificationMailer.with(article: article).deliver_later
414
- end
415
- end
416
- ```
362
+ *Bengt-Ove Hollaender*
417
363
 
418
- *Jean Boussier*
364
+ * Use ntuples to populate row_count instead of count for Postgres
419
365
 
420
- * Add `ActiveRecord::Base.current_transaction`.
366
+ *Jonathan Calvert*
421
367
 
422
- Returns the current transaction, to allow registering callbacks on it.
368
+ * Fix checking whether an unpersisted record is `include?`d in a strictly
369
+ loaded `has_and_belongs_to_many` association.
423
370
 
424
- ```ruby
425
- Article.current_transaction.after_commit do
426
- PublishNotificationMailer.with(article: article).deliver_later
427
- end
428
- ```
371
+ *Hartley McGuire*
429
372
 
430
- *Jean Boussier*
373
+ * Add ability to change transaction isolation for all pools within a block.
431
374
 
432
- * Add `ActiveRecord.after_all_transactions_commit` callback.
375
+ This functionality is useful if your application needs to change the database
376
+ transaction isolation for a request or action.
433
377
 
434
- Useful for code that may run either inside or outside a transaction and needs
435
- to perform work after the state changes have been properly persisted.
378
+ Calling `ActiveRecord.with_transaction_isolation_level(level) {}` in an around filter or
379
+ middleware will set the transaction isolation for all pools accessed within the block,
380
+ but not for the pools that aren't.
381
+
382
+ This works with explicit and implicit transactions:
436
383
 
437
384
  ```ruby
438
- def publish_article(article)
439
- article.update(published: true)
440
- ActiveRecord.after_all_transactions_commit do
441
- PublishNotificationMailer.with(article: article).deliver_later
385
+ ActiveRecord.with_transaction_isolation_level(:read_committed) do
386
+ Tag.transaction do # opens a transaction explicitly
387
+ Tag.create!
442
388
  end
443
389
  end
444
390
  ```
445
391
 
446
- In the above example, the block is either executed immediately if called outside
447
- of a transaction, or called after the open transaction is committed.
448
-
449
- If the transaction is rolled back, the block isn't called.
450
-
451
- *Jean Boussier*
452
-
453
- * Add the ability to ignore counter cache columns until they are backfilled.
454
-
455
- Starting to use counter caches on existing large tables can be troublesome, because the column
456
- values must be backfilled separately of the column addition (to not lock the table for too long)
457
- and before the use of `:counter_cache` (otherwise methods like `size`/`any?`/etc, which use
458
- counter caches internally, can produce incorrect results). People usually use database triggers
459
- or callbacks on child associations while backfilling before introducing a counter cache
460
- configuration to the association.
461
-
462
- Now, to safely backfill the column, while keeping the column updated with child records added/removed, use:
463
-
464
392
  ```ruby
465
- class Comment < ApplicationRecord
466
- belongs_to :post, counter_cache: { active: false }
393
+ ActiveRecord.with_transaction_isolation_level(:read_committed) do
394
+ Tag.create! # opens a transaction implicitly
467
395
  end
468
396
  ```
469
397
 
470
- While the counter cache is not "active", the methods like `size`/`any?`/etc will not use it,
471
- but get the results directly from the database. After the counter cache column is backfilled, simply
472
- remove the `{ active: false }` part from the counter cache definition, and it will now be used by the
473
- mentioned methods.
474
-
475
- *fatkodima*
398
+ *Eileen M. Uchitelle*
476
399
 
477
- * Retry known idempotent SELECT queries on connection-related exceptions.
400
+ * Raise `ActiveRecord::MissingRequiredOrderError` when order dependent finder methods (e.g. `#first`, `#last`) are
401
+ called without `order` values on the relation, and the model does not have any order columns (`implicit_order_column`,
402
+ `query_constraints`, or `primary_key`) to fall back on.
478
403
 
479
- SELECT queries we construct by walking the Arel tree and / or with known model attributes
480
- are idempotent and can safely be retried in the case of a connection error. Previously,
481
- adapters such as `TrilogyAdapter` would raise `ActiveRecord::ConnectionFailed: Trilogy::EOFError`
482
- when encountering a connection error mid-request.
404
+ This change will be introduced with a new framework default for Rails 8.1, and the current behavior of not raising
405
+ an error has been deprecated with the aim of removing the configuration option in Rails 8.2.
483
406
 
484
- *Adrianna Chang*
407
+ ```ruby
408
+ config.active_record.raise_on_missing_required_finder_order_columns = true
409
+ ```
485
410
 
486
- * Allow association's `foreign_key` to be composite.
411
+ *Joshua Young*
487
412
 
488
- `query_constraints` option was the only way to configure a composite foreign key by passing an `Array`.
489
- Now it's possible to pass an Array value as `foreign_key` to achieve the same behavior of an association.
413
+ * `:class_name` is now invalid in polymorphic `belongs_to` associations.
490
414
 
491
- *Nikita Vasilevsky*
415
+ Reason is `:class_name` does not make sense in those associations because
416
+ the class name of target records is dynamic and stored in the type column.
492
417
 
493
- * Allow association's `primary_key` to be composite.
418
+ Existing polymorphic associations setting this option can just delete it.
419
+ While it did not raise, it had no effect anyway.
494
420
 
495
- Association's `primary_key` can be composite when derived from associated model `primary_key` or `query_constraints`.
496
- Now it's possible to explicitly set it as composite on the association.
421
+ *Xavier Noria*
497
422
 
498
- *Nikita Vasilevsky*
423
+ * Add support for multiple databases to `db:migrate:reset`.
499
424
 
500
- * Add `config.active_record.permanent_connection_checkout` setting.
425
+ *Joé Dupuis*
501
426
 
502
- Controls whether `ActiveRecord::Base.connection` raises an error, emits a deprecation warning, or neither.
427
+ * Add `affected_rows` to `ActiveRecord::Result`.
503
428
 
504
- `ActiveRecord::Base.connection` checkouts a database connection from the pool and keeps it leased until the end of
505
- the request or job. This behavior can be undesirable in environments that use many more threads or fibers than there
506
- is available connections.
429
+ *Jenny Shen*
507
430
 
508
- This configuration can be used to track down and eliminate code that calls `ActiveRecord::Base.connection` and
509
- migrate it to use `ActiveRecord::Base.with_connection` instead.
431
+ * Enable passing retryable SqlLiterals to `#where`.
510
432
 
511
- The default behavior remains unchanged, and there is currently no plans to change the default.
433
+ *Hartley McGuire*
512
434
 
513
- *Jean Boussier*
435
+ * Set default for primary keys in `insert_all`/`upsert_all`.
514
436
 
515
- * Add dirties option to uncached.
437
+ Previously in Postgres, updating and inserting new records in one upsert wasn't possible
438
+ due to null primary key values. `nil` primary key values passed into `insert_all`/`upsert_all`
439
+ are now implicitly set to the default insert value specified by adapter.
516
440
 
517
- This adds a `dirties` option to `ActiveRecord::Base.uncached` and
518
- `ActiveRecord::ConnectionAdapters::ConnectionPool#uncached`.
441
+ *Jenny Shen*
519
442
 
520
- When set to `true` (the default), writes will clear all query caches belonging to the current thread.
521
- When set to `false`, writes to the affected connection pool will not clear any query cache.
443
+ * Add a load hook `active_record_database_configurations` for `ActiveRecord::DatabaseConfigurations`
522
444
 
523
- This is needed by Solid Cache so that cache writes do not clear query caches.
445
+ *Mike Dalessio*
524
446
 
525
- *Donal McBreen*
447
+ * Use `TRUE` and `FALSE` for SQLite queries with boolean columns.
526
448
 
527
- * Deprecate `ActiveRecord::Base.connection` in favor of `.lease_connection`.
449
+ *Hartley McGuire*
528
450
 
529
- The method has been renamed as `lease_connection` to better reflect that the returned
530
- connection will be held for the duration of the request or job.
451
+ * Bump minimum supported SQLite to 3.23.0.
531
452
 
532
- This deprecation is a soft deprecation, no warnings will be issued and there is no
533
- current plan to remove the method.
453
+ *Hartley McGuire*
534
454
 
535
- *Jean Boussier*
455
+ * Allow allocated Active Records to lookup associations.
536
456
 
537
- * Deprecate `ActiveRecord::ConnectionAdapters::ConnectionPool#connection`.
457
+ Previously, the association cache isn't setup on allocated record objects, so association
458
+ lookups will crash. Test frameworks like mocha use allocate to check for stubbable instance
459
+ methods, which can trigger an association lookup.
538
460
 
539
- The method has been renamed as `lease_connection` to better reflect that the returned
540
- connection will be held for the duration of the request or job.
461
+ *Gannon McGibbon*
541
462
 
542
- *Jean Boussier*
463
+ * Encryption now supports `support_unencrypted_data: true` being set per-attribute.
543
464
 
544
- * Expose a generic fixture accessor for fixture names that may conflict with Minitest.
465
+ Previously this only worked if `ActiveRecord::Encryption.config.support_unencrypted_data == true`.
466
+ Now, if the global config is turned off, you can still opt in for a specific attribute.
545
467
 
546
468
  ```ruby
547
- assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
548
- assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
469
+ # ActiveRecord::Encryption.config.support_unencrypted_data = true
470
+ class User < ActiveRecord::Base
471
+ encrypts :name, support_unencrypted_data: false # only supports encrypted data
472
+ encrypts :email # supports encrypted or unencrypted data
473
+ end
549
474
  ```
550
475
 
551
- *Jean Boussier*
552
-
553
- * Using `Model.query_constraints` with a single non-primary-key column used to raise as expected, but with an
554
- incorrect error message.
555
-
556
- This has been fixed to raise with a more appropriate error message.
557
-
558
- *Joshua Young*
559
-
560
- * Fix `has_one` association autosave setting the foreign key attribute when it is unchanged.
561
-
562
- This behavior is also inconsistent with autosaving `belongs_to` and can have unintended side effects like raising
563
- an `ActiveRecord::ReadonlyAttributeError` when the foreign key attribute is marked as read-only.
564
-
565
- *Joshua Young*
566
-
567
- * Remove deprecated behavior that would rollback a transaction block when exited using `return`, `break` or `throw`.
568
-
569
- *Rafael Mendonça França*
570
-
571
- * Deprecate `Rails.application.config.active_record.commit_transaction_on_non_local_return`.
572
-
573
- *Rafael Mendonça França*
574
-
575
- * Remove deprecated support to pass `rewhere` to `ActiveRecord::Relation#merge`.
576
-
577
- *Rafael Mendonça França*
578
-
579
- * Remove deprecated support to pass `deferrable: true` to `add_foreign_key`.
580
-
581
- *Rafael Mendonça França*
582
-
583
- * Remove deprecated support to quote `ActiveSupport::Duration`.
584
-
585
- *Rafael Mendonça França*
586
-
587
- * Remove deprecated `#quote_bound_value`.
588
-
589
- *Rafael Mendonça França*
590
-
591
- * Remove deprecated `ActiveRecord::ConnectionAdapters::ConnectionPool#connection_klass`.
592
-
593
- *Rafael Mendonça França*
594
-
595
- * Remove deprecated support to apply `#connection_pool_list`, `#active_connections?`, `#clear_active_connections!`,
596
- `#clear_reloadable_connections!`, `#clear_all_connections!` and `#flush_idle_connections!` to the connections pools
597
- for the current role when the `role` argument isn't provided.
598
-
599
- *Rafael Mendonça França*
600
-
601
- * Remove deprecated `#all_connection_pools`.
476
+ ```ruby
477
+ # ActiveRecord::Encryption.config.support_unencrypted_data = false
478
+ class User < ActiveRecord::Base
479
+ encrypts :name, support_unencrypted_data: true # supports encrypted or unencrypted data
480
+ encrypts :email # only supports encrypted data
481
+ end
482
+ ```
602
483
 
603
- *Rafael Mendonça França*
484
+ *Alex Ghiculescu*
604
485
 
605
- * Remove deprecated `ActiveRecord::ConnectionAdapters::SchemaCache#data_sources`.
486
+ * Model generator no longer needs a database connection to validate column types.
606
487
 
607
- *Rafael Mendonça França*
488
+ *Mike Dalessio*
608
489
 
609
- * Remove deprecated `ActiveRecord::ConnectionAdapters::SchemaCache.load_from`.
490
+ * Allow signed ID verifiers to be configurable via `Rails.application.message_verifiers`
610
491
 
611
- *Rafael Mendonça França*
492
+ Prior to this change, the primary way to configure signed ID verifiers was
493
+ to set `signed_id_verifier` on each model class:
612
494
 
613
- * Remove deprecated `#all_foreign_keys_valid?` from database adapters.
495
+ ```ruby
496
+ Post.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
497
+ Comment.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
498
+ ```
614
499
 
615
- *Rafael Mendonça França*
500
+ And if the developer did not set `signed_id_verifier`, a verifier would be
501
+ instantiated with a secret derived from `secret_key_base` and the following
502
+ options:
616
503
 
617
- * Remove deprecated support to passing coder and class as second argument to `serialize`.
504
+ ```ruby
505
+ { digest: "SHA256", serializer: JSON, url_safe: true }
506
+ ```
618
507
 
619
- *Rafael Mendonça França*
508
+ Thus it was cumbersome to rotate configuration for all verifiers.
620
509
 
621
- * Remove deprecated support to `ActiveRecord::Base#read_attribute(:id)` to return the custom primary key value.
510
+ This change defines a new Rails config: [`config.active_record.use_legacy_signed_id_verifier`][].
511
+ The default value is `:generate_and_verify`, which preserves the previous
512
+ behavior. However, when set to `:verify`, signed ID verifiers will use
513
+ configuration from `Rails.application.message_verifiers` (specifically,
514
+ `Rails.application.message_verifiers["active_record/signed_id"]`) to
515
+ generate and verify signed IDs, but will also verify signed IDs using the
516
+ older configuration.
622
517
 
623
- *Rafael Mendonça França*
518
+ To avoid complication, the new behavior only applies when `signed_id_verifier_secret`
519
+ is not set on a model class or any of its ancestors. Additionally,
520
+ `signed_id_verifier_secret` is now deprecated. If you are currently setting
521
+ `signed_id_verifier_secret` on a model class, you can set `signed_id_verifier`
522
+ instead:
624
523
 
625
- * Remove deprecated `TestFixtures.fixture_path`.
524
+ ```ruby
525
+ # BEFORE
526
+ Post.signed_id_verifier_secret = "my secret"
626
527
 
627
- *Rafael Mendonça França*
528
+ # AFTER
529
+ Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("my secret", digest: "SHA256", serializer: JSON, url_safe: true)
530
+ ```
628
531
 
629
- * Remove deprecated behavior to support referring to a singular association by its plural name.
532
+ To ease migration, `signed_id_verifier` has also been changed to behave as a
533
+ `class_attribute` (i.e. inheritable), but _only when `signed_id_verifier_secret`
534
+ is not set_:
630
535
 
631
- *Rafael Mendonça França*
536
+ ```ruby
537
+ # BEFORE
538
+ ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
539
+ Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
632
540
 
633
- * Deprecate `Rails.application.config.active_record.allow_deprecated_singular_associations_name`.
541
+ # AFTER
542
+ ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
543
+ Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => true
634
544
 
635
- *Rafael Mendonça França*
545
+ Post.signed_id_verifier_secret = "my secret" # => deprecation warning
546
+ Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
547
+ ```
636
548
 
637
- * Remove deprecated support to passing `SchemaMigration` and `InternalMetadata` classes as arguments to
638
- `ActiveRecord::MigrationContext`.
549
+ Note, however, that it is recommended to eventually migrate from
550
+ model-specific verifiers to a unified configuration managed by
551
+ `Rails.application.message_verifiers`. `ActiveSupport::MessageVerifier#rotate`
552
+ can facilitate that transition. For example:
639
553
 
640
- *Rafael Mendonça França*
554
+ ```ruby
555
+ # BEFORE
556
+ # Generate and verify signed Post IDs using Post-specific configuration
557
+ Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("post secret", ...)
641
558
 
642
- * Remove deprecated `ActiveRecord::Migration.check_pending!` method.
559
+ # AFTER
560
+ # Generate and verify signed Post IDs using the unified configuration
561
+ Post.signed_id_verifier = Post.signed_id_verifier.dup
562
+ # Fall back to Post-specific configuration when verifying signed IDs
563
+ Post.signed_id_verifier.rotate("post secret", ...)
564
+ ```
643
565
 
644
- *Rafael Mendonça França*
566
+ [`config.active_record.use_legacy_signed_id_verifier`]: https://guides.rubyonrails.org/v8.1/configuring.html#config-active-record-use-legacy-signed-id-verifier
645
567
 
646
- * Remove deprecated `ActiveRecord::LogSubscriber.runtime` method.
568
+ *Ali Sepehri*, *Jonathan Hefner*
647
569
 
648
- *Rafael Mendonça França*
570
+ * Prepend `extra_flags` in postgres' `structure_load`
649
571
 
650
- * Remove deprecated `ActiveRecord::LogSubscriber.runtime=` method.
572
+ When specifying `structure_load_flags` with a postgres adapter, the flags
573
+ were appended to the default flags, instead of prepended.
574
+ This caused issues with flags not being taken into account by postgres.
651
575
 
652
- *Rafael Mendonça França*
576
+ *Alice Loeser*
653
577
 
654
- * Remove deprecated `ActiveRecord::LogSubscriber.reset_runtime` method.
578
+ * Allow bypassing primary key/constraint addition in `implicit_order_column`
655
579
 
656
- *Rafael Mendonça França*
580
+ When specifying multiple columns in an array for `implicit_order_column`, adding
581
+ `nil` as the last element will prevent appending the primary key to order
582
+ conditions. This allows more precise control of indexes used by
583
+ generated queries. It should be noted that this feature does introduce the risk
584
+ of API misbehavior if the specified columns are not fully unique.
657
585
 
658
- * Remove deprecated support to define `explain` in the connection adapter with 2 arguments.
586
+ *Issy Long*
659
587
 
660
- *Rafael Mendonça França*
588
+ * Allow setting the `schema_format` via database configuration.
661
589
 
662
- * Remove deprecated `ActiveRecord::ActiveJobRequiredError`.
590
+ ```
591
+ primary:
592
+ schema_format: ruby
593
+ ```
663
594
 
664
- *Rafael Mendonça França*
595
+ Useful for multi-database setups when apps require different formats per-database.
665
596
 
666
- * Remove deprecated `ActiveRecord::Base.clear_active_connections!`.
597
+ *T S Vallender*
667
598
 
668
- *Rafael Mendonça França*
599
+ * Support disabling indexes for MySQL v8.0.0+ and MariaDB v10.6.0+
669
600
 
670
- * Remove deprecated `ActiveRecord::Base.clear_reloadable_connections!`.
601
+ MySQL 8.0.0 added an option to disable indexes from being used by the query
602
+ optimizer by making them "invisible". This allows the index to still be maintained
603
+ and updated but no queries will be permitted to use it. This can be useful for adding
604
+ new invisible indexes or making existing indexes invisible before dropping them
605
+ to ensure queries are not negatively affected.
606
+ See https://dev.mysql.com/blog-archive/mysql-8-0-invisible-indexes/ for more details.
671
607
 
672
- *Rafael Mendonça França*
608
+ MariaDB 10.6.0 also added support for this feature by allowing indexes to be "ignored"
609
+ in queries. See https://mariadb.com/kb/en/ignored-indexes/ for more details.
673
610
 
674
- * Remove deprecated `ActiveRecord::Base.clear_all_connections!`.
611
+ Active Record now supports this option for MySQL 8.0.0+ and MariaDB 10.6.0+ for
612
+ index creation and alteration where the new index option `enabled: true/false` can be
613
+ passed to column and index methods as below:
675
614
 
676
- *Rafael Mendonça França*
615
+ ```ruby
616
+ add_index :users, :email, enabled: false
617
+ enable_index :users, :email
618
+ add_column :users, :dob, :string, index: { enabled: false }
619
+
620
+ change_table :users do |t|
621
+ t.index :name, enabled: false
622
+ t.index :dob
623
+ t.disable_index :dob
624
+ t.column :username, :string, index: { enabled: false }
625
+ t.references :account, index: { enabled: false }
626
+ end
677
627
 
678
- * Remove deprecated `ActiveRecord::Base.flush_idle_connections!`.
628
+ create_table :users do |t|
629
+ t.string :name, index: { enabled: false }
630
+ t.string :email
631
+ t.index :email, enabled: false
632
+ end
633
+ ```
679
634
 
680
- *Rafael Mendonça França*
635
+ *Merve Taner*
681
636
 
682
- * Remove deprecated `name` argument from `ActiveRecord::Base.remove_connection`.
637
+ * Respect `implicit_order_column` in `ActiveRecord::Relation#reverse_order`.
683
638
 
684
- *Rafael Mendonça França*
639
+ *Joshua Young*
685
640
 
686
- * Remove deprecated support to call `alias_attribute` with non-existent attribute names.
641
+ * Add column types to `ActiveRecord::Result` for SQLite3.
687
642
 
688
- *Rafael Mendonça França*
643
+ *Andrew Kane*
689
644
 
690
- * Remove deprecated `Rails.application.config.active_record.suppress_multiple_database_warning`.
645
+ * Raise `ActiveRecord::ReadOnlyError` when pessimistically locking with a readonly role.
691
646
 
692
- *Rafael Mendonça França*
647
+ *Joshua Young*
693
648
 
694
- * Add `ActiveRecord::Encryption::MessagePackMessageSerializer`.
649
+ * Fix using the `SQLite3Adapter`'s `dbconsole` method outside of a Rails application.
695
650
 
696
- Serialize data to the MessagePack format, for efficient storage in binary columns.
651
+ *Hartley McGuire*
697
652
 
698
- The binary encoding requires around 30% less space than the base64 encoding
699
- used by the default serializer.
653
+ * Fix migrating multiple databases with `ActiveRecord::PendingMigration` action.
700
654
 
701
- *Donal McBreen*
655
+ *Gannon McGibbon*
702
656
 
703
- * Add support for encrypting binary columns.
657
+ * Enable automatically retrying idempotent association queries on connection
658
+ errors.
704
659
 
705
- Ensure encryption and decryption pass `Type::Binary::Data` around for binary data.
660
+ *Hartley McGuire*
706
661
 
707
- Previously encrypting binary columns with the `ActiveRecord::Encryption::MessageSerializer`
708
- incidentally worked for MySQL and SQLite, but not PostgreSQL.
662
+ * Add `allow_retry` to `sql.active_record` instrumentation.
709
663
 
710
- *Donal McBreen*
664
+ This enables identifying queries which queries are automatically retryable on connection errors.
711
665
 
712
- * Deprecated `ENV["SCHEMA_CACHE"]` in favor of `schema_cache_path` in the database configuration.
666
+ *Hartley McGuire*
713
667
 
714
- *Rafael Mendonça França*
668
+ * Better support UPDATE with JOIN for Postgresql and SQLite3
715
669
 
716
- * Add `ActiveRecord::Base.with_connection` as a shortcut for leasing a connection for a short duration.
670
+ Previously when generating update queries with one or more JOIN clauses,
671
+ Active Record would use a sub query which would prevent to reference the joined
672
+ tables in the `SET` clause, for instance:
717
673
 
718
- The leased connection is yielded, and for the duration of the block, any call to `ActiveRecord::Base.connection`
719
- will yield that same connection.
674
+ ```ruby
675
+ Comment.joins(:post).update_all("title = posts.title")
676
+ ```
720
677
 
721
- This is useful to perform a few database operations without causing a connection to be leased for the
722
- entire duration of the request or job.
678
+ This is now supported as long as the relation doesn't also use a `LIMIT`, `ORDER` or
679
+ `GROUP BY` clause. This was supported by the MySQL adapter for a long time.
723
680
 
724
681
  *Jean Boussier*
725
682
 
726
- * Deprecate `config.active_record.warn_on_records_fetched_greater_than` now that `sql.active_record`
727
- notification includes `:row_count` field.
728
-
729
- *Jason Nochlin*
683
+ * Introduce a before-fork hook in `ActiveSupport::Testing::Parallelization` to clear existing
684
+ connections, to avoid fork-safety issues with the mysql2 adapter.
730
685
 
731
- * The fix ensures that the association is joined using the appropriate join type
732
- (either inner join or left outer join) based on the existing joins in the scope.
686
+ Fixes #41776
733
687
 
734
- This prevents unintentional overrides of existing join types and ensures consistency in the generated SQL queries.
735
-
736
- Example:
737
-
738
-
739
-
740
- ```ruby
741
- # `associated` will use `LEFT JOIN` instead of using `JOIN`
742
- Post.left_joins(:author).where.associated(:author)
743
- ```
688
+ *Mike Dalessio*, *Donal McBreen*
744
689
 
745
- *Saleh Alhaddad*
690
+ * PoolConfig no longer keeps a reference to the connection class.
746
691
 
747
- * Fix an issue where `ActiveRecord::Encryption` configurations are not ready before the loading
748
- of Active Record models, when an application is eager loaded. As a result, encrypted attributes
749
- could be misconfigured in some cases.
692
+ Keeping a reference to the class caused subtle issues when combined with reloading in
693
+ development. Fixes #54343.
750
694
 
751
- *Maxime Réty*
695
+ *Mike Dalessio*
752
696
 
753
- * Deprecate defining an `enum` with keyword arguments.
697
+ * Fix SQL notifications sometimes not sent when using async queries.
754
698
 
755
699
  ```ruby
756
- class Function > ApplicationRecord
757
- # BAD
758
- enum color: [:red, :blue],
759
- type: [:instance, :class]
760
-
761
- # GOOD
762
- enum :color, [:red, :blue]
763
- enum :type, [:instance, :class]
700
+ Post.async_count
701
+ ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) do
702
+ Post.count
764
703
  end
765
704
  ```
766
705
 
767
- *Hartley McGuire*
768
-
769
- * Add `config.active_record.validate_migration_timestamps` option for validating migration timestamps.
770
-
771
- When set, validates that the timestamp prefix for a migration is no more than a day ahead of
772
- the timestamp associated with the current time. This is designed to prevent migrations prefixes
773
- from being hand-edited to future timestamps, which impacts migration generation and other
774
- migration commands.
775
-
776
- *Adrianna Chang*
777
-
778
- * Properly synchronize `Mysql2Adapter#active?` and `TrilogyAdapter#active?`.
779
-
780
- As well as `disconnect!` and `verify!`.
781
-
782
- This generally isn't a big problem as connections must not be shared between
783
- threads, but is required when running transactional tests or system tests
784
- and could lead to a SEGV.
785
-
786
- *Jean Boussier*
706
+ In rare circumstances and under the right race condition, Active Support notifications
707
+ would no longer be dispatched after using an asynchronous query.
708
+ This is now fixed.
787
709
 
788
- * Support `:source_location` tag option for query log tags.
710
+ *Edouard Chin*
789
711
 
790
- ```ruby
791
- config.active_record.query_log_tags << :source_location
792
- ```
712
+ * Eliminate queries loading dumped schema cache on Postgres
793
713
 
794
- Calculating the caller location is a costly operation and should be used primarily in development
795
- (note, there is also a `config.active_record.verbose_query_logs` that serves the same purpose)
796
- or occasionally on production for debugging purposes.
797
-
798
- *fatkodima*
714
+ Improve resiliency by avoiding needing to open a database connection to load the
715
+ type map while defining attribute methods at boot when a schema cache file is
716
+ configured on PostgreSQL databases.
799
717
 
800
- * Add an option to `ActiveRecord::Encryption::Encryptor` to disable compression.
718
+ *James Coleman*
801
719
 
802
- Allow compression to be disabled by setting `compress: false`
720
+ * `ActiveRecord::Coder::JSON` can be instantiated
803
721
 
722
+ Options can now be passed to `ActiveRecord::Coder::JSON` when instantiating the coder. This allows:
804
723
  ```ruby
805
- class User
806
- encrypts :name, encryptor: ActiveRecord::Encryption::Encryptor.new(compress: false)
807
- end
724
+ serialize :config, coder: ActiveRecord::Coder::JSON.new(symbolize_names: true)
808
725
  ```
726
+ *matthaigh27*
809
727
 
810
- *Donal McBreen*
811
-
812
- * Deprecate passing strings to `ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename`.
813
-
814
- A `ActiveRecord::DatabaseConfigurations::DatabaseConfig` object should be passed instead.
815
-
816
- *Rafael Mendonça França*
817
-
818
- * Add `row_count` field to `sql.active_record` notification.
819
-
820
- This field returns the amount of rows returned by the query that emitted the notification.
821
-
822
- This metric is useful in cases where one wants to detect queries with big result sets.
823
-
824
- *Marvin Bitterlich*
825
-
826
- * Consistently raise an `ArgumentError` when passing an invalid argument to a nested attributes association writer.
827
-
828
- Previously, this would only raise on collection associations and produce a generic error on singular associations.
829
-
830
- Now, it will raise on both collection and singular associations.
831
-
832
- *Joshua Young*
833
-
834
- * Fix single quote escapes on default generated MySQL columns.
728
+ * Deprecate using `insert_all`/`upsert_all` with unpersisted records in associations.
835
729
 
836
- MySQL 5.7.5+ supports generated columns, which can be used to create a column that is computed from an expression.
730
+ Using these methods on associations containing unpersisted records will now
731
+ show a deprecation warning, as the unpersisted records will be lost after
732
+ the operation.
837
733
 
838
- Previously, the schema dump would output a string with double escapes for generated columns with single quotes in the default expression.
734
+ *Nick Schwaderer*
839
735
 
840
- This would result in issues when importing the schema on a fresh instance of a MySQL database.
736
+ * Make column name optional for `index_exists?`.
841
737
 
842
- Now, the string will not be escaped and will be valid Ruby upon importing of the schema.
738
+ This aligns well with `remove_index` signature as well, where
739
+ index name doesn't need to be derived from the column names.
843
740
 
844
- *Yash Kapadia*
741
+ *Ali Ismayiliov*
845
742
 
846
- * Fix Migrations with versions older than 7.1 validating options given to
847
- `add_reference` and `t.references`.
743
+ * Change the payload name of `sql.active_record` notification for eager
744
+ loading from "SQL" to "#{model.name} Eager Load".
848
745
 
849
- *Hartley McGuire*
746
+ *zzak*
850
747
 
851
- * Add `<role>_types` class method to `ActiveRecord::DelegatedType` so that the delegated types can be introspected.
748
+ * Enable automatically retrying idempotent `#exists?` queries on connection
749
+ errors.
852
750
 
853
- *JP Rosevear*
751
+ *Hartley McGuire*, *classidied*
854
752
 
855
- * Make `schema_dump`, `query_cache`, `replica` and `database_tasks` configurable via `DATABASE_URL`.
753
+ * Deprecate usage of unsupported methods in conjunction with `update_all`:
856
754
 
857
- This wouldn't always work previously because boolean values would be interpreted as strings.
755
+ `update_all` will now print a deprecation message if a query includes either `WITH`,
756
+ `WITH RECURSIVE` or `DISTINCT` statements. Those were never supported and were ignored
757
+ when generating the SQL query.
858
758
 
859
- e.g. `DATABASE_URL=postgres://localhost/foo?schema_dump=false` now properly disable dumping the schema
860
- cache.
759
+ An error will be raised in a future Rails release. This behavior will be consistent
760
+ with `delete_all` which currently raises an error for unsupported statements.
861
761
 
862
- *Mike Coutermarsh*, *Jean Boussier*
762
+ *Edouard Chin*
863
763
 
864
- * Introduce `ActiveRecord::Transactions::ClassMethods#set_callback`.
764
+ * The table columns inside `schema.rb` are now sorted alphabetically.
865
765
 
866
- It is identical to `ActiveSupport::Callbacks::ClassMethods#set_callback`
867
- but with support for `after_commit` and `after_rollback` callback options.
766
+ Previously they'd be sorted by creation order, which can cause merge conflicts when two
767
+ branches modify the same table concurrently.
868
768
 
869
- *Joshua Young*
769
+ *John Duff*
870
770
 
871
- * Make `ActiveRecord::Encryption::Encryptor` agnostic of the serialization format used for encrypted data.
771
+ * Introduce versions formatter for the schema dumper.
872
772
 
873
- Previously, the encryptor instance only allowed an encrypted value serialized as a `String` to be passed to the message serializer.
773
+ It is now possible to override how schema dumper formats versions information inside the
774
+ `structure.sql` file. Currently, the versions are simply sorted in the decreasing order.
775
+ Within large teams, this can potentially cause many merge conflicts near the top of the list.
874
776
 
875
- Now, the encryptor lets the configured `message_serializer` decide which types of serialized encrypted values are supported. A custom serialiser is therefore allowed to serialize `ActiveRecord::Encryption::Message` objects using a type other than `String`.
777
+ Now, the custom formatter can be provided with a custom sorting logic (e.g. by hash values
778
+ of the versions), which can greatly reduce the number of conflicts.
876
779
 
877
- The default `ActiveRecord::Encryption::MessageSerializer` already ensures that only `String` objects are passed for deserialization.
780
+ *fatkodima*
878
781
 
879
- *Maxime Réty*
782
+ * Serialized attributes can now be marked as comparable.
880
783
 
881
- * Fix `encrypted_attribute?` to take into account context properties passed to `encrypts`.
784
+ A not rare issue when working with serialized attributes is that the serialized representation of an object
785
+ can change over time. Either because you are migrating from one serializer to the other (e.g. YAML to JSON or to msgpack),
786
+ or because the serializer used subtly changed its output.
882
787
 
883
- *Maxime Réty*
788
+ One example is libyaml that used to have some extra trailing whitespaces, and recently fixed that.
789
+ When this sorts of thing happen, you end up with lots of records that report being changed even though
790
+ 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.
884
791
 
885
- * The object returned by `explain` now responds to `pluck`, `first`,
886
- `last`, `average`, `count`, `maximum`, `minimum`, and `sum`. Those
887
- new methods run `EXPLAIN` on the corresponding queries:
792
+ The solution is to instead compare the deserialized representation of the object, however Active Record
793
+ can't assume the deserialized object has a working `==` method. Hence why this new functionality is opt-in.
888
794
 
889
795
  ```ruby
890
- User.all.explain.count
891
- # EXPLAIN SELECT COUNT(*) FROM `users`
892
- # ...
893
-
894
- User.all.explain.maximum(:id)
895
- # EXPLAIN SELECT MAX(`users`.`id`) FROM `users`
896
- # ...
897
- ```
898
-
899
- *Petrik de Heus*
900
-
901
- * Fixes an issue where `validates_associated` `:on` option wasn't respected
902
- when validating associated records.
903
-
904
- *Austen Madden*, *Alex Ghiculescu*, *Rafał Brize*
905
-
906
- * Allow overriding SQLite defaults from `database.yml`.
907
-
908
- Any PRAGMA configuration set under the `pragmas` key in the configuration
909
- file takes precedence over Rails' defaults, and additional PRAGMAs can be
910
- set as well.
911
-
912
- ```yaml
913
- database: storage/development.sqlite3
914
- timeout: 5000
915
- pragmas:
916
- journal_mode: off
917
- temp_store: memory
796
+ serialize :config, type: Hash, coder: JSON, comparable: true
918
797
  ```
919
798
 
920
- *Stephen Margheim*
921
-
922
- * Remove warning message when running SQLite in production, but leave it unconfigured.
923
-
924
- There are valid use cases for running SQLite in production. However, it must be done
925
- with care, so instead of a warning most users won't see anyway, it's preferable to
926
- leave the configuration commented out to force them to think about having the database
927
- on a persistent volume etc.
928
-
929
- *Jacopo Beschi*, *Jean Boussier*
930
-
931
- * Add support for generated columns to the SQLite3 adapter.
932
-
933
- Generated columns (both stored and dynamic) are supported since version 3.31.0 of SQLite.
934
- This adds support for those to the SQLite3 adapter.
799
+ *Jean Boussier*
935
800
 
936
- ```ruby
937
- create_table :users do |t|
938
- t.string :name
939
- t.virtual :name_upper, type: :string, as: 'UPPER(name)'
940
- t.virtual :name_lower, type: :string, as: 'LOWER(name)', stored: true
941
- end
942
- ```
801
+ * Fix MySQL default functions getting dropped when changing a column's nullability.
943
802
 
944
- *Stephen Margheim*
803
+ *Bastian Bartmann*
945
804
 
946
- * TrilogyAdapter: ignore `host` if `socket` parameter is set.
805
+ * SQLite extensions can be configured in `config/database.yml`.
947
806
 
948
- This allows to configure a connection on a UNIX socket via `DATABASE_URL`:
807
+ The database configuration option `extensions:` allows an application to load SQLite extensions
808
+ when using `sqlite3` >= v2.4.0. The array members may be filesystem paths or the names of
809
+ modules that respond to `.to_path`:
949
810
 
950
- ```
951
- DATABASE_URL=trilogy://does-not-matter/my_db_production?socket=/var/run/mysql.sock
811
+ ``` yaml
812
+ development:
813
+ adapter: sqlite3
814
+ extensions:
815
+ - SQLean::UUID # module name responding to `.to_path`
816
+ - .sqlpkg/nalgeon/crypto/crypto.so # or a filesystem path
817
+ - <%= AppExtensions.location %> # or ruby code returning a path
952
818
  ```
953
819
 
954
- *Jean Boussier*
820
+ *Mike Dalessio*
955
821
 
956
- * Make `assert_queries_count`, `assert_no_queries`, `assert_queries_match`, and
957
- `assert_no_queries_match` assertions public.
822
+ * `ActiveRecord::Middleware::ShardSelector` supports granular database connection switching.
958
823
 
959
- To assert the expected number of queries are made, Rails internally uses `assert_queries_count` and
960
- `assert_no_queries`. To assert that specific SQL queries are made, `assert_queries_match` and
961
- `assert_no_queries_match` are used. These assertions can now be used in applications as well.
824
+ A new configuration option, `class_name:`, is introduced to
825
+ `config.active_record.shard_selector` to allow an application to specify the abstract connection
826
+ class to be switched by the shard selection middleware. The default class is
827
+ `ActiveRecord::Base`.
962
828
 
963
- ```ruby
964
- class ArticleTest < ActiveSupport::TestCase
965
- test "queries are made" do
966
- assert_queries_count(1) { Article.first }
967
- end
829
+ For example, this configuration tells `ShardSelector` to switch shards using
830
+ `AnimalsRecord.connected_to`:
968
831
 
969
- test "creates a foreign key" do
970
- assert_queries_match(/ADD FOREIGN KEY/i, include_schema: true) do
971
- @connection.add_foreign_key(:comments, :posts)
972
- end
973
- end
974
- end
975
832
  ```
976
-
977
- *Petrik de Heus*, *fatkodima*
978
-
979
- * Fix `has_secure_token` calls the setter method on initialize.
980
-
981
- *Abeid Ahmed*
982
-
983
- * When using a `DATABASE_URL`, allow for a configuration to map the protocol in the URL to a specific database
984
- adapter. This allows decoupling the adapter the application chooses to use from the database connection details
985
- set in the deployment environment.
986
-
987
- ```ruby
988
- # ENV['DATABASE_URL'] = "mysql://localhost/example_database"
989
- config.active_record.protocol_adapters.mysql = "trilogy"
990
- # will connect to MySQL using the trilogy adapter
833
+ config.active_record.shard_selector = { class_name: "AnimalsRecord" }
991
834
  ```
992
835
 
993
- *Jean Boussier*, *Kevin McPhillips*
836
+ *Mike Dalessio*
994
837
 
995
- * In cases where MySQL returns `warning_count` greater than zero, but returns no warnings when
996
- the `SHOW WARNINGS` query is executed, `ActiveRecord.db_warnings_action` proc will still be
997
- called with a generic warning message rather than silently ignoring the warning(s).
838
+ * Reset relations after `insert_all`/`upsert_all`.
998
839
 
999
- *Kevin McPhillips*
840
+ Bulk insert/upsert methods will now call `reset` if used on a relation, matching the behavior of `update_all`.
1000
841
 
1001
- * `DatabaseConfigurations#configs_for` accepts a symbol in the `name` parameter.
842
+ *Milo Winningham*
1002
843
 
1003
- *Andrew Novoselac*
844
+ * Use `_N` as a parallel tests databases suffixes
1004
845
 
1005
- * Fix `where(field: values)` queries when `field` is a serialized attribute
1006
- (for example, when `field` uses `ActiveRecord::Base.serialize` or is a JSON
1007
- column).
846
+ Peviously, `-N` was used as a suffix. This can cause problems for RDBMSes
847
+ which do not support dashes in database names.
1008
848
 
1009
- *João Alves*
849
+ *fatkodima*
1010
850
 
1011
- * Make the output of `ActiveRecord::Core#inspect` configurable.
851
+ * Remember when a database connection has recently been verified (for
852
+ two seconds, by default), to avoid repeated reverifications during a
853
+ single request.
1012
854
 
1013
- By default, calling `inspect` on a record will yield a formatted string including just the `id`.
855
+ This should recreate a similar rate of verification as in Rails 7.1,
856
+ where connections are leased for the duration of a request, and thus
857
+ only verified once.
1014
858
 
1015
- ```ruby
1016
- Post.first.inspect #=> "#<Post id: 1>"
1017
- ```
859
+ *Matthew Draper*
1018
860
 
1019
- The attributes to be included in the output of `inspect` can be configured with
1020
- `ActiveRecord::Core#attributes_for_inspect`.
861
+ * Allow to reset cache counters for multiple records.
1021
862
 
1022
- ```ruby
1023
- Post.attributes_for_inspect = [:id, :title]
1024
- Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
1025
863
  ```
1026
-
1027
- With `attributes_for_inspect` set to `:all`, `inspect` will list all the record's attributes.
1028
-
1029
- ```ruby
1030
- Post.attributes_for_inspect = :all
1031
- Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
864
+ Aircraft.reset_counters([1, 2, 3], :wheels_count)
1032
865
  ```
1033
866
 
1034
- In `development` and `test` mode, `attributes_for_inspect` will be set to `:all` by default.
1035
-
1036
- You can also call `full_inspect` to get an inspection with all the attributes.
867
+ It produces much fewer queries compared to the custom implementation using looping over ids.
868
+ Previously: `O(ids.size * counters.size)` queries, now: `O(ids.size + counters.size)` queries.
1037
869
 
1038
- The attributes in `attribute_for_inspect` will also be used for `pretty_print`.
1039
-
1040
- *Andrew Novoselac*
1041
-
1042
- * Don't mark attributes as changed when reassigned to `Float::INFINITY` or
1043
- `-Float::INFINITY`.
1044
-
1045
- *Maicol Bentancor*
870
+ *fatkodima*
1046
871
 
1047
- * Support the `RETURNING` clause for MariaDB.
872
+ * Add `affected_rows` to `sql.active_record` Notification.
1048
873
 
1049
- *fatkodima*, *Nikolay Kondratyev*
874
+ *Hartley McGuire*
1050
875
 
1051
- * The SQLite3 adapter now implements the `supports_deferrable_constraints?` contract.
876
+ * Fix `sum` when performing a grouped calculation.
1052
877
 
1053
- Allows foreign keys to be deferred by adding the `:deferrable` key to the `foreign_key` options.
878
+ `User.group(:friendly).sum` no longer worked. This is fixed.
1054
879
 
1055
- ```ruby
1056
- add_reference :person, :alias, foreign_key: { deferrable: :deferred }
1057
- add_reference :alias, :person, foreign_key: { deferrable: :deferred }
1058
- ```
880
+ *Edouard Chin*
1059
881
 
1060
- *Stephen Margheim*
882
+ * Add support for enabling or disabling transactional tests per database.
1061
883
 
1062
- * Add the `set_constraints` helper to PostgreSQL connections.
884
+ A test class can now override the default `use_transactional_tests` setting
885
+ for individual databases, which can be useful if some databases need their
886
+ current state to be accessible to an external process while tests are running.
1063
887
 
1064
888
  ```ruby
1065
- Post.create!(user_id: -1) # => ActiveRecord::InvalidForeignKey
1066
-
1067
- Post.transaction do
1068
- Post.connection.set_constraints(:deferred)
1069
- p = Post.create!(user_id: -1)
1070
- u = User.create!
1071
- p.user = u
1072
- p.save!
889
+ class MostlyTransactionalTest < ActiveSupport::TestCase
890
+ self.use_transactional_tests = true
891
+ skip_transactional_tests_for_database :shared
1073
892
  end
1074
893
  ```
1075
894
 
1076
- *Cody Cutrer*
1077
-
1078
- * Include `ActiveModel::API` in `ActiveRecord::Base`.
1079
-
1080
- *Sean Doyle*
1081
-
1082
- * Ensure `#signed_id` outputs `url_safe` strings.
895
+ *Matthew Cheetham*, *Morgan Mareve*
1083
896
 
1084
- *Jason Meller*
897
+ * Cast `query_cache` value when using URL configuration.
1085
898
 
1086
- * Add `nulls_last` and working `desc.nulls_first` for MySQL.
899
+ *zzak*
1087
900
 
1088
- *Tristan Fellows*
901
+ * NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
1089
902
 
1090
- * Allow for more complex hash arguments for `order` which mimics `where` in `ActiveRecord::Relation`.
903
+ *Ryuta Kamizono*
1091
904
 
1092
- ```ruby
1093
- Topic.includes(:posts).order(posts: { created_at: :desc })
1094
- ```
905
+ * `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
1095
906
 
1096
- *Myles Boone*
907
+ *Kazuma Watanabe*
1097
908
 
1098
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/activerecord/CHANGELOG.md) for previous changes.
909
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/activerecord/CHANGELOG.md) for previous changes.