activerecord 7.2.4 → 8.1.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1013 -878
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/association.rb +69 -27
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +36 -8
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +7 -3
- data/lib/active_record/associations/collection_proxy.rb +26 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency.rb +3 -2
- data/lib/active_record/associations/preloader/association.rb +3 -3
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +18 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attributes.rb +3 -0
- data/lib/active_record/autosave_association.rb +69 -27
- data/lib/active_record/base.rb +1 -2
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/column_serializer.rb +1 -1
- data/lib/active_record/coders/json.rb +16 -6
- data/lib/active_record/coders/yaml_column.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +429 -93
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +148 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +27 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +32 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +124 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +129 -63
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +132 -65
- data/lib/active_record/connection_adapters/column.rb +14 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -66
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -10
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +79 -61
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +14 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +71 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +156 -68
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +78 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +15 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +104 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +41 -66
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +15 -18
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +25 -2
- data/lib/active_record/core.rb +33 -17
- data/lib/active_record/counter_cache.rb +35 -8
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +74 -9
- data/lib/active_record/database_configurations/url_config.rb +15 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +5 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +8 -8
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
- data/lib/active_record/encryption/encryptor.rb +28 -8
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +33 -30
- data/lib/active_record/errors.rb +33 -9
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +76 -0
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +15 -9
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +9 -4
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +31 -29
- data/lib/active_record/message_pack.rb +13 -0
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +56 -13
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +48 -42
- data/lib/active_record/model_schema.rb +40 -15
- data/lib/active_record/nested_attributes.rb +14 -12
- data/lib/active_record/persistence.rb +163 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +100 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +21 -9
- data/lib/active_record/railtie.rb +35 -30
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -38
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +54 -22
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +60 -43
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +73 -43
- data/lib/active_record/relation/merger.rb +12 -10
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +9 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +23 -8
- data/lib/active_record/relation/query_attribute.rb +3 -1
- data/lib/active_record/relation/query_methods.rb +200 -96
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +2 -9
- data/lib/active_record/relation.rb +127 -87
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +17 -10
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/signed_id.rb +44 -16
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +53 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +83 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +4 -58
- data/lib/active_record/tasks/postgresql_database_tasks.rb +7 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +18 -4
- data/lib/active_record/test_fixtures.rb +52 -6
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +56 -32
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +6 -11
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +7 -2
- data/lib/arel/table.rb +3 -7
- data/lib/arel/visitors/dot.rb +0 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +4 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +15 -12
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
data/CHANGELOG.md
CHANGED
|
@@ -1,1459 +1,1594 @@
|
|
|
1
|
-
## Rails
|
|
1
|
+
## Rails 8.1.4 (September 24, 2026) ##
|
|
2
2
|
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
Fixes #57183.
|
|
3
|
+
* Avoid deadlocks when concurrent `find_or_create_by` calls read back the same
|
|
4
|
+
record within MySQL transactions.
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
Use a shared lock for the read after a duplicate insert, preserving visibility
|
|
7
|
+
under REPEATABLE READ without upgrading competing shared locks to exclusive locks.
|
|
8
|
+
This also applies to `create_or_find_by` and the bang variants of both methods.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Fixes #54281.
|
|
11
11
|
|
|
12
|
-
*
|
|
12
|
+
*Kirsten Westeinde*
|
|
13
13
|
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
Better handle asynchronous exceptions being thrown inside
|
|
17
|
-
the `reconnect!` method.
|
|
18
|
-
|
|
19
|
-
This may fixes some deep errors such as:
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
undefined method `key?' for nil:NilClass (NoMethodError)
|
|
23
|
-
if !type_map.key?(oid)
|
|
24
|
-
```
|
|
14
|
+
* Filter the database password out of failed `db:` task command error messages.
|
|
25
15
|
|
|
26
|
-
*
|
|
16
|
+
*Ngan Pham*
|
|
27
17
|
|
|
28
|
-
* Fix `
|
|
18
|
+
* Fix `ActiveRecord::TypeCaster::Connection` sometimes leaking a checked-out
|
|
19
|
+
connection.
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
*Hartley McGuire*
|
|
31
22
|
|
|
32
|
-
|
|
23
|
+
* Fix PostgreSQL exclusion constraints with multiline expressions being parsed
|
|
24
|
+
incorrectly during schema introspection.
|
|
33
25
|
|
|
26
|
+
*Jake McAllister*
|
|
34
27
|
|
|
35
|
-
|
|
28
|
+
* Fix async `ActiveRecord::StatementCache#execute` raising an error for
|
|
29
|
+
out-of-range bind values instead of returning an empty result.
|
|
36
30
|
|
|
37
|
-
*
|
|
31
|
+
*viralpraxis*
|
|
38
32
|
|
|
33
|
+
* Fix `where` clauses with column-tuple syntax not resolving references to
|
|
34
|
+
other tables.
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
*Chris Gunther*
|
|
41
37
|
|
|
42
|
-
*
|
|
38
|
+
* Fix `distinct: true` being ignored by `average`.
|
|
43
39
|
|
|
40
|
+
*Kenta Ishizaki*
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
* Fix `belongs_to` change tracking for composite foreign keys.
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
Only the first foreign key column was checked for changes; now all foreign
|
|
45
|
+
key columns are checked.
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
`ON DELETE CASCADE` foreign keys, ActiveRecord would silently delete all
|
|
51
|
-
data from the child tables. This occurred because SQLite requires table
|
|
52
|
-
recreation for schema changes, and during this process the original table
|
|
53
|
-
is temporarily dropped, triggering CASCADE deletes on child tables.
|
|
47
|
+
*Anas Khan*
|
|
54
48
|
|
|
55
|
-
|
|
56
|
-
wrapped `disable_referential_integrity` inside a transaction, but
|
|
57
|
-
`PRAGMA foreign_keys` cannot be modified inside a transaction in SQLite -
|
|
58
|
-
attempting to do so simply has no effect. This meant foreign keys remained
|
|
59
|
-
enabled during table recreation, causing CASCADE deletes to fire.
|
|
49
|
+
* Make `add_column(if_not_exists: true)` reversible.
|
|
60
50
|
|
|
61
|
-
|
|
62
|
-
procedure: `disable_referential_integrity` now wraps the transaction instead
|
|
63
|
-
of being wrapped by it. This ensures foreign keys are properly disabled
|
|
64
|
-
before the transaction starts and re-enabled after it commits, preventing
|
|
65
|
-
CASCADE deletes while maintaining data integrity through atomic transactions.
|
|
51
|
+
*Kenta Ishizaki*
|
|
66
52
|
|
|
67
|
-
|
|
53
|
+
* Quote the index name in MySQL `enable_index` and `disable_index`.
|
|
68
54
|
|
|
69
|
-
|
|
55
|
+
Unquoted index names containing special characters could cause SQL syntax
|
|
56
|
+
errors.
|
|
70
57
|
|
|
71
|
-
|
|
72
|
-
only the optional part of the key should be cleared.
|
|
58
|
+
*Kenta Ishizaki*
|
|
73
59
|
|
|
74
|
-
|
|
60
|
+
* Make `remove_foreign_key(if_exists: true)` reversible.
|
|
75
61
|
|
|
76
|
-
*
|
|
62
|
+
*Kenta Ishizaki*
|
|
77
63
|
|
|
78
|
-
|
|
64
|
+
* Fix `distinct: true` being ignored by grouped `sum`.
|
|
79
65
|
|
|
80
|
-
*
|
|
66
|
+
*Kenta Ishizaki*
|
|
81
67
|
|
|
82
|
-
|
|
68
|
+
* Return an `ActiveRecord::Promise` from `async_ids` on a contradictory
|
|
69
|
+
relation, instead of a plain `ActiveRecord::Result`.
|
|
83
70
|
|
|
84
|
-
*
|
|
71
|
+
*Kenta Ishizaki*
|
|
85
72
|
|
|
86
|
-
|
|
73
|
+
* Fix reversibility check for `drop_virtual_table`.
|
|
87
74
|
|
|
88
|
-
|
|
75
|
+
The wrong argument was extracted, so the check for whether options were
|
|
76
|
+
given could pass or fail incorrectly.
|
|
89
77
|
|
|
90
|
-
*
|
|
78
|
+
*Kenta Ishizaki*
|
|
91
79
|
|
|
92
|
-
* Fix
|
|
80
|
+
* Fix `remove_check_constraint(if_exists: true)` incorrectly raising when
|
|
81
|
+
removing by expression.
|
|
93
82
|
|
|
94
|
-
|
|
83
|
+
The `if_exists` check did not pass the expression to
|
|
84
|
+
`check_constraint_exists?`, so it could not find the constraint.
|
|
95
85
|
|
|
96
|
-
*
|
|
86
|
+
*Kenta Ishizaki*
|
|
97
87
|
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
* Clear PostgreSQL notices as they are handled, preventing warnings from
|
|
89
|
+
leaking to subsequent queries.
|
|
100
90
|
|
|
101
|
-
|
|
91
|
+
*Matthew Draper*
|
|
102
92
|
|
|
103
|
-
|
|
93
|
+
* Fix `WeakThreadKeyMap` raising "can't add a new key into hash during
|
|
94
|
+
iteration" when connections are checked in from multiple threads.
|
|
104
95
|
|
|
105
|
-
*
|
|
96
|
+
*Matthew Draper*
|
|
106
97
|
|
|
107
|
-
|
|
98
|
+
* Continue pool disconnect after a connection's cleanup or disconnect raises.
|
|
108
99
|
|
|
109
|
-
|
|
100
|
+
Previously, a failure on one connection aborted the teardown, stranding
|
|
101
|
+
remaining connections and their resources.
|
|
110
102
|
|
|
111
|
-
|
|
112
|
-
class, causing nedless extra autosaves.
|
|
103
|
+
*Matthew Draper*
|
|
113
104
|
|
|
114
|
-
|
|
105
|
+
* Fix race condition between `preconnect` and the connection pool reaper.
|
|
115
106
|
|
|
116
|
-
*
|
|
107
|
+
*Yasuo Honda*
|
|
117
108
|
|
|
118
|
-
|
|
109
|
+
* Fix `in_order_of` raising when the column is a CTE reference.
|
|
119
110
|
|
|
120
|
-
*
|
|
111
|
+
*viralpraxis*
|
|
121
112
|
|
|
122
|
-
|
|
113
|
+
* Fix `content_columns` including composite primary key components.
|
|
123
114
|
|
|
124
|
-
|
|
115
|
+
Only the first primary key column was excluded; now all primary key columns
|
|
116
|
+
are excluded.
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
base = Comment.joins(:post).where(user_id: 1).where("recent = 1")
|
|
128
|
-
puts base.merge(base.where(draft: true).or(Post.where(archived: true))).to_sql
|
|
129
|
-
```
|
|
118
|
+
*Kenta Ishizaki*
|
|
130
119
|
|
|
131
|
-
|
|
120
|
+
* Treat `remove_column` with options but no type as irreversible.
|
|
132
121
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
WHERE (recent = 1)
|
|
137
|
-
AND (
|
|
138
|
-
"comments"."user_id" = 1
|
|
139
|
-
AND (recent = 1)
|
|
140
|
-
AND "comments"."draft" = 1
|
|
141
|
-
OR "posts"."archived" = 1
|
|
142
|
-
)
|
|
143
|
-
```
|
|
122
|
+
Previously, `remove_column(:table, :column, default: nil)` would not raise
|
|
123
|
+
`IrreversibleMigration` because the options hash was mistaken for a column
|
|
124
|
+
type.
|
|
144
125
|
|
|
145
|
-
|
|
126
|
+
*Kenta Ishizaki*
|
|
146
127
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
|
|
150
|
-
WHERE "comments"."user_id" = 1
|
|
151
|
-
AND (recent = 1)
|
|
152
|
-
AND (
|
|
153
|
-
"comments"."user_id" = 1
|
|
154
|
-
AND (recent = 1)
|
|
155
|
-
AND "comments"."draft" = 1
|
|
156
|
-
OR "posts"."archived" = 1
|
|
157
|
-
)
|
|
158
|
-
```
|
|
128
|
+
* Fix `counter_cache_column` crashing when `:counter_cache` is given as a
|
|
129
|
+
Hash without a `:column` key.
|
|
159
130
|
|
|
160
|
-
*
|
|
131
|
+
*Kenta Ishizaki*
|
|
161
132
|
|
|
162
|
-
*
|
|
133
|
+
* Coerce `seeds` and `use_metadata_table` to booleans in `UrlConfig`.
|
|
163
134
|
|
|
164
|
-
|
|
135
|
+
When configured via `DATABASE_URL`, these options were left as strings
|
|
136
|
+
instead of being coerced to booleans like `replica` and `database_tasks`.
|
|
165
137
|
|
|
166
|
-
*
|
|
138
|
+
*Kenta Ishizaki*
|
|
167
139
|
|
|
168
|
-
|
|
140
|
+
* Fix `excluding` (and its `without` alias) to work with composite primary key
|
|
141
|
+
models. Records passed to `excluding` are now matched by their full composite id
|
|
142
|
+
instead of being looked up by a single primary key column.
|
|
169
143
|
|
|
170
|
-
*
|
|
171
|
-
loaded `has_and_belongs_to_many` association.
|
|
144
|
+
*Kenta Ishizaki*
|
|
172
145
|
|
|
173
|
-
|
|
146
|
+
* Fix `Relation#delete` raising on a single composite primary key id.
|
|
174
147
|
|
|
175
|
-
|
|
148
|
+
`Model.delete(id)` now wraps a single composite id in an array before building
|
|
149
|
+
the `WHERE` clause, so a single record can be deleted by its composite id.
|
|
176
150
|
|
|
177
|
-
*
|
|
151
|
+
*Kenta Ishizaki*
|
|
178
152
|
|
|
179
|
-
*
|
|
153
|
+
* Fix reading a composite primary key after a partial `select` returning the
|
|
154
|
+
raw value instead of `nil` for unselected key columns.
|
|
180
155
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
156
|
+
The attribute defaults builder excluded only the single primary key column from
|
|
157
|
+
defaults; for composite primary keys it left the unselected key columns in the
|
|
158
|
+
defaults, so `record.id` returned an array of raw column values instead of
|
|
159
|
+
`[nil, nil]`. All primary key columns are now excluded.
|
|
184
160
|
|
|
185
|
-
*
|
|
161
|
+
*Kenta Ishizaki*
|
|
186
162
|
|
|
187
|
-
*
|
|
163
|
+
* Fix `find` with an empty array on a composite primary key model returning the
|
|
164
|
+
argument array instead of `[]`.
|
|
188
165
|
|
|
189
|
-
|
|
166
|
+
`Model.find([])` now returns a fresh empty array for composite primary key
|
|
167
|
+
models, matching single-key models.
|
|
190
168
|
|
|
191
|
-
|
|
192
|
-
the most common being with the PostgreSQLAdapter raising `undefined method 'key?' for nil`
|
|
193
|
-
or `TypeError: wrong argument type nil (expected PG::TypeMap)`.
|
|
169
|
+
*Kenta Ishizaki*
|
|
194
170
|
|
|
195
|
-
|
|
171
|
+
* Fix `find` with an order clause and an offset past the end of the ids raising
|
|
172
|
+
`RecordNotFound` instead of returning an empty result.
|
|
196
173
|
|
|
197
|
-
*
|
|
174
|
+
*Kenta Ishizaki*
|
|
198
175
|
|
|
199
|
-
|
|
176
|
+
* Fix `in_order_of` dropping values that cannot be serialized for the column
|
|
177
|
+
instead of turning them into an `IS NULL` match.
|
|
200
178
|
|
|
201
|
-
|
|
179
|
+
Out-of-range integers and unknown enum keys are now ignored rather than
|
|
180
|
+
silently matching rows with `NULL` in that column. When all requested values
|
|
181
|
+
are unrepresentable, the relation returns no rows instead of building an empty
|
|
182
|
+
`CASE` expression.
|
|
202
183
|
|
|
203
|
-
|
|
204
|
-
comparing it with the minimum required version for the adapter. This meant that the connection could
|
|
205
|
-
never be successfully configured on subsequent reconnection attempts.
|
|
184
|
+
*Kenta Ishizaki*
|
|
206
185
|
|
|
207
|
-
|
|
208
|
-
and ensuring the version isn't cached, which allows the version to be retrieved on the next connection attempt.
|
|
186
|
+
* Fix stale `finder_needs_type_condition?` memo after the schema cache is reloaded.
|
|
209
187
|
|
|
210
|
-
|
|
188
|
+
When an STI model's `type` column was removed and re-added (e.g. via a
|
|
189
|
+
migration) and `reset_column_information` was called, the cached
|
|
190
|
+
`finder_needs_type_condition` value was not cleared, so queries could omit the
|
|
191
|
+
STI type condition. The memo is now reset on `reload_schema_from_cache`.
|
|
211
192
|
|
|
212
|
-
*
|
|
193
|
+
*Kenta Ishizaki*
|
|
213
194
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
the most common being with the PostgreSQLAdapter raising `undefined method `key?' for nil`
|
|
217
|
-
or `TypeError: wrong argument type nil (expected PG::TypeMap)`.
|
|
195
|
+
* Fix PostgreSQL schema dump to qualify `enum_type` when the same enum name exists
|
|
196
|
+
in different schemas.
|
|
218
197
|
|
|
219
|
-
|
|
198
|
+
Previously the dumped `enum_type` used the bare type name, which could resolve to
|
|
199
|
+
the wrong enum in another schema. It now uses the schema-qualified name.
|
|
220
200
|
|
|
221
|
-
*
|
|
201
|
+
*fatkodima*
|
|
222
202
|
|
|
223
|
-
|
|
203
|
+
* Fix PostgreSQL index introspection to parse opclasses from another schema.
|
|
224
204
|
|
|
225
|
-
|
|
205
|
+
Index expressions using a schema-qualified opclass (e.g.
|
|
206
|
+
`USING gin(position test_schema.gin_trgm_ops)`) are now parsed correctly so the
|
|
207
|
+
opclass is captured without the schema prefix.
|
|
226
208
|
|
|
227
|
-
*
|
|
209
|
+
*Nicolas Vandenboegaerde*
|
|
228
210
|
|
|
229
|
-
*
|
|
211
|
+
* Fix `belongs_to` `:touch` with composite foreign keys.
|
|
230
212
|
|
|
231
|
-
|
|
213
|
+
Touching the parent record when a `belongs_to` with a composite foreign key
|
|
214
|
+
changes or is destroyed now correctly resolves the old and new parent by all
|
|
215
|
+
foreign key columns.
|
|
232
216
|
|
|
233
|
-
*
|
|
217
|
+
*Romulo Storel*
|
|
234
218
|
|
|
235
|
-
|
|
219
|
+
* Fix `add_index` `comment:` option on a schema-qualified PostgreSQL table.
|
|
236
220
|
|
|
237
|
-
|
|
221
|
+
The `COMMENT ON INDEX` statement now schema-qualifies the index name, so the
|
|
222
|
+
comment is applied to the index in the correct schema instead of raising.
|
|
238
223
|
|
|
239
|
-
*
|
|
224
|
+
*Tobias Egli*
|
|
240
225
|
|
|
241
|
-
* Fix
|
|
226
|
+
* Fix `check_all_foreign_keys_valid!` on PostgreSQL partitioned tables.
|
|
242
227
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
end
|
|
228
|
+
The validation query previously matched constraints by name across all tables in
|
|
229
|
+
the schema, marking unrelated constraints (including partition children) as not
|
|
230
|
+
validated. It now scopes the update to the specific table.
|
|
247
231
|
|
|
248
|
-
|
|
249
|
-
scope :active, -> {
|
|
250
|
-
joins("JOIN students ON instructor_roles.student_id = students.id")
|
|
251
|
-
.where(students { status: 1 })
|
|
252
|
-
}
|
|
253
|
-
end
|
|
232
|
+
*Alexis Andrieu*
|
|
254
233
|
|
|
255
|
-
|
|
256
|
-
```
|
|
234
|
+
* Revert stable sorting of columns and indexes in serialized schema caches.
|
|
257
235
|
|
|
258
|
-
|
|
259
|
-
|
|
236
|
+
`SchemaCache#encode_with` no longer sorts a table's columns and indexes by name
|
|
237
|
+
when writing the cache, restoring the pre-8.1 behavior.
|
|
260
238
|
|
|
261
239
|
*Jean Boussier*
|
|
262
240
|
|
|
263
|
-
* Fix
|
|
241
|
+
* Fix `only_columns` to enumerate columns in the `SELECT` clause.
|
|
264
242
|
|
|
265
|
-
|
|
243
|
+
Models using `only_columns` were generating `SELECT *` instead of an explicit
|
|
244
|
+
column list, which could select columns that were meant to be excluded.
|
|
266
245
|
|
|
267
|
-
*
|
|
246
|
+
*sarub0b0*
|
|
268
247
|
|
|
269
|
-
|
|
248
|
+
* Fix `eager_load` with a composite primary key and an explicit `select`.
|
|
270
249
|
|
|
271
|
-
|
|
250
|
+
The join dependency used the single primary key value to build aliases; for
|
|
251
|
+
composite primary keys it now uses the full array of primary key columns, so
|
|
252
|
+
eager loading with a custom `select` no longer drops the association records.
|
|
272
253
|
|
|
273
|
-
*
|
|
254
|
+
*fatkodima*
|
|
274
255
|
|
|
275
|
-
* Fix
|
|
256
|
+
* Fix `find_signed` with a composite primary key.
|
|
276
257
|
|
|
277
|
-
|
|
278
|
-
|
|
258
|
+
`find_signed` now wraps the decoded id in an array so `find_by` matches against
|
|
259
|
+
all primary key columns, instead of silently returning `nil`.
|
|
279
260
|
|
|
280
|
-
|
|
281
|
-
Post.create!(author: User.find(1)) # Fail if user is invalid
|
|
282
|
-
```
|
|
261
|
+
*Kenta Ishizaki*
|
|
283
262
|
|
|
284
|
-
|
|
263
|
+
* Fix `with_connection(prevent_permanent_checkout: true)` clearing a sticky lease
|
|
264
|
+
that was already set by `lease_connection`.
|
|
285
265
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
266
|
+
A `with_connection` call with `prevent_permanent_checkout: true` no longer resets
|
|
267
|
+
`lease.sticky` to its previous value when the connection was already sticky, so
|
|
268
|
+
the connection remains checked out after the block.
|
|
289
269
|
|
|
290
|
-
|
|
291
|
-
where connections are leased for the duration of a request, and thus
|
|
292
|
-
only verified once.
|
|
270
|
+
*Ben Sheldon*
|
|
293
271
|
|
|
294
|
-
|
|
272
|
+
* Fix `reset_counters` to cast string ids to the primary key type.
|
|
295
273
|
|
|
296
|
-
|
|
274
|
+
`reset_counters` called with a string id (the form ids take from request params)
|
|
275
|
+
failed to find the record for both single and composite primary keys. Each id is
|
|
276
|
+
now cast against its own column type.
|
|
297
277
|
|
|
298
|
-
*
|
|
299
|
-
|
|
300
|
-
* Fix a race condition in `ActiveRecord::Base#method_missing` when lazily defining attributes.
|
|
278
|
+
*fatkodima*
|
|
301
279
|
|
|
302
|
-
|
|
303
|
-
it could result in a `NoMethodError` being raised.
|
|
280
|
+
* Fix `belongs_to` presence validation for composite foreign keys.
|
|
304
281
|
|
|
305
|
-
|
|
282
|
+
The required-association validation only checked the first foreign key column.
|
|
283
|
+
For composite foreign keys it now considers the association present only when
|
|
284
|
+
none of the foreign key columns are `nil`, and changed when any of them changed.
|
|
306
285
|
|
|
307
|
-
*
|
|
286
|
+
*Felix Descoteaux*
|
|
308
287
|
|
|
309
|
-
|
|
288
|
+
* Fix preloading a `belongs_to` with a composite foreign key when some key columns
|
|
289
|
+
are `nil`.
|
|
310
290
|
|
|
311
|
-
|
|
312
|
-
|
|
291
|
+
The preloader now skips owners whose composite key has any `nil` component
|
|
292
|
+
instead of issuing a query that matches unrelated rows.
|
|
313
293
|
|
|
314
|
-
*
|
|
294
|
+
*Rose Wiegley*
|
|
315
295
|
|
|
316
|
-
* Fix
|
|
296
|
+
* Fix `belongs_to` inverse matching with composite foreign keys.
|
|
317
297
|
|
|
318
|
-
|
|
298
|
+
`inversable?` compared a single foreign key column against a single primary key,
|
|
299
|
+
so `belongs_to` associations with composite foreign keys never matched their
|
|
300
|
+
inverse. Foreign key and primary key values are now compared component by
|
|
301
|
+
component.
|
|
319
302
|
|
|
320
|
-
*
|
|
303
|
+
*Martin Samson*
|
|
321
304
|
|
|
322
|
-
|
|
305
|
+
* Fix `validate_table_length!` to ignore the schema prefix on PostgreSQL.
|
|
323
306
|
|
|
324
|
-
|
|
307
|
+
Schema-qualified table names (e.g. `"schema.very_long_table_name"`) were
|
|
308
|
+
incorrectly rejected as exceeding the table name length limit because the schema
|
|
309
|
+
prefix was counted. The schema is now stripped before checking the length.
|
|
325
310
|
|
|
326
311
|
*fatkodima*
|
|
327
312
|
|
|
328
|
-
* Fix
|
|
313
|
+
* Fix passing Trilogy SSL options to `mysql` and `mysqldump` commands.
|
|
329
314
|
|
|
330
|
-
*
|
|
315
|
+
*Ngan Pham*
|
|
331
316
|
|
|
332
|
-
* Fix
|
|
317
|
+
* Fix `keepalive: false` in `database.yml` falling back to the
|
|
318
|
+
600 second default.
|
|
333
319
|
|
|
334
|
-
*
|
|
320
|
+
*Joe Sak*
|
|
335
321
|
|
|
336
|
-
*
|
|
322
|
+
* Fix connection checkout blocking past the configured `checkout_timeout` while
|
|
323
|
+
waiting behind background connection maintenance.
|
|
337
324
|
|
|
338
|
-
|
|
325
|
+
`ConnectionPool#try_to_queue_for_background_connection` waited up to a
|
|
326
|
+
hardcoded 100 seconds for a connection tied up in maintenance (e.g. a keepalive
|
|
327
|
+
ping), regardless of the pool's configured `checkout_timeout`. If maintenance
|
|
328
|
+
stalled (a slow or unresponsive database server), checkout could block for far
|
|
329
|
+
longer than the caller asked for.
|
|
339
330
|
|
|
340
|
-
*
|
|
331
|
+
*Joe Sak*
|
|
341
332
|
|
|
342
|
-
|
|
333
|
+
* Fix encrypted fixtures for JSON columns.
|
|
343
334
|
|
|
344
|
-
|
|
335
|
+
Encrypted fixture values were serialized twice: once by the encrypted
|
|
336
|
+
attribute type and again by the column type when the rows were inserted.
|
|
337
|
+
For `json`/`jsonb` columns this stored the encrypted payload as a JSON
|
|
338
|
+
string, which then failed to decrypt. The payload is now handed back in
|
|
339
|
+
the column's cast form so it round-trips through the column type.
|
|
345
340
|
|
|
346
|
-
*
|
|
341
|
+
*Carlos Daniel Pohlod*
|
|
347
342
|
|
|
348
|
-
*
|
|
343
|
+
* Fix performance regression in `method_missing` for virtual SELECT alias
|
|
344
|
+
attributes.
|
|
349
345
|
|
|
350
|
-
|
|
346
|
+
Fixes #57183.
|
|
351
347
|
|
|
352
|
-
*
|
|
348
|
+
*Hammad Khan*
|
|
353
349
|
|
|
354
|
-
|
|
350
|
+
* Column defaults are no longer eagerly deserialized.
|
|
355
351
|
|
|
352
|
+
Restore the Active Record 8.0 and older behavior.
|
|
353
|
+
Column defaults are now whatever is returned by the database, generally a string.
|
|
356
354
|
|
|
357
|
-
|
|
355
|
+
This was changed in 8.1.0 to make the attribute API more consistent,
|
|
356
|
+
however it caused problems when the attribute type is later changed in the model.
|
|
358
357
|
|
|
359
|
-
|
|
358
|
+
Typically, some databases treat boolean columns as small integers, ance once the
|
|
359
|
+
default integer is casted to a boolean, it's not longer possible to change the
|
|
360
|
+
attribute back into an integer in the model.
|
|
360
361
|
|
|
361
|
-
|
|
362
|
+
Before:
|
|
362
363
|
|
|
363
|
-
|
|
364
|
+
```ruby
|
|
365
|
+
Person.columns_hash["age"].default # => 0
|
|
366
|
+
```
|
|
364
367
|
|
|
368
|
+
After:
|
|
365
369
|
|
|
366
|
-
|
|
370
|
+
```ruby
|
|
371
|
+
Person.columns_hash["age"].default # => "0"
|
|
372
|
+
```
|
|
367
373
|
|
|
368
|
-
|
|
374
|
+
See https://github.com/rails/rails/issues/58292.
|
|
369
375
|
|
|
376
|
+
*Jean Boussier*
|
|
370
377
|
|
|
371
|
-
|
|
378
|
+
* Preserve the declared parent order when dumping PostgreSQL `INHERITS` table options.
|
|
372
379
|
|
|
373
|
-
|
|
380
|
+
The schema dumper read a table's inherited parents without an `ORDER BY`, so the
|
|
381
|
+
`INHERITS (...)` clause in `schema.rb` could be emitted in a nondeterministic order.
|
|
382
|
+
Parents are now ordered by `pg_inherits.inhseqno`.
|
|
374
383
|
|
|
375
|
-
|
|
384
|
+
*viralpraxis*
|
|
376
385
|
|
|
377
|
-
|
|
386
|
+
* Preserve SQLite partial and expression indexes when their stored SQL contains newlines.
|
|
378
387
|
|
|
379
|
-
*
|
|
388
|
+
*Javi Ramírez*
|
|
380
389
|
|
|
381
|
-
|
|
390
|
+
* Only use multi statement for `SET TRANSACTION ISOLATION LEVEL; BEGIN` if
|
|
391
|
+
MySQL connection is configured to use multi statement.
|
|
382
392
|
|
|
383
|
-
|
|
393
|
+
*Eliseu Daroit*, *Hartley McGuire*, *Matthew Draper*
|
|
384
394
|
|
|
385
|
-
|
|
395
|
+
* Mark a connection unverified when a non-`StandardError` interrupts a query.
|
|
386
396
|
|
|
387
|
-
|
|
397
|
+
A query interrupted by a non-`StandardError`, such as a fiber scheduler's
|
|
398
|
+
cancel or a `Timeout`, leaves the connection desynced. Active Record
|
|
399
|
+
previously returned it to the pool still marked verified, so the next
|
|
400
|
+
checkout reused it and failed on a dead socket. The connection is now
|
|
401
|
+
marked unverified, so it re-verifies and reconnects before its next use.
|
|
388
402
|
|
|
389
|
-
*
|
|
403
|
+
*Eliseu Daroit*
|
|
390
404
|
|
|
391
|
-
* Fix
|
|
405
|
+
* Fix `has_many` and `has_one` associations on a new record returning an empty
|
|
406
|
+
result when the owner has a composite primary key, even when every primary
|
|
407
|
+
key column is populated.
|
|
392
408
|
|
|
393
|
-
|
|
394
|
-
But associations that would only contain unsaved records would be skipped.
|
|
409
|
+
*Jean-Samuel Aubry-Guzzi*
|
|
395
410
|
|
|
396
|
-
|
|
411
|
+
* Fix inverse association matching for `has_many` and `has_one` associations
|
|
412
|
+
with association-specific composite primary keys.
|
|
397
413
|
|
|
398
|
-
*
|
|
414
|
+
*Hugo Vacher*
|
|
399
415
|
|
|
400
|
-
|
|
416
|
+
* Fix `ActiveRecord::Base.with` to call `Object#with` when given a block.
|
|
401
417
|
|
|
402
|
-
|
|
403
|
-
|
|
418
|
+
The class-level `with` delegates to the relation's CTE query method, which
|
|
419
|
+
does not accept a block. When a block is passed, it now delegates to
|
|
420
|
+
`Object#with` instead, so it can be used to temporarily set attributes on
|
|
421
|
+
the class for the duration of the block.
|
|
404
422
|
|
|
405
|
-
*
|
|
423
|
+
*Janko Marohnić*
|
|
406
424
|
|
|
407
|
-
* Fix
|
|
425
|
+
* Fix `serialize` with `coder: ActiveRecord::Coders::JSON` silently double-encoding
|
|
426
|
+
a native `json`/`jsonb` column.
|
|
408
427
|
|
|
409
|
-
*
|
|
428
|
+
*Kenta Ishizaki*
|
|
410
429
|
|
|
411
|
-
* Fix `
|
|
430
|
+
* Fix `update_all` / `delete_all` ignoring `group` and `having`, updating or
|
|
431
|
+
deleting every row in the table instead of only the rows that satisfy the
|
|
432
|
+
`HAVING` clause.
|
|
412
433
|
|
|
413
|
-
|
|
434
|
+
*Kenta Ishizaki*
|
|
414
435
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
has_one :middle, dependent: :destroy
|
|
418
|
-
has_one :right, through: :middle
|
|
419
|
-
end
|
|
436
|
+
* Fix `ActiveRecord::Relation#cache_key` / `cache_version` for a loaded collection
|
|
437
|
+
containing a record without a timestamp.
|
|
420
438
|
|
|
421
|
-
|
|
422
|
-
belongs_to :left, dependent: :destroy
|
|
423
|
-
belongs_to :right, dependent: :destroy
|
|
424
|
-
end
|
|
439
|
+
*Kenta Ishizaki*
|
|
425
440
|
|
|
426
|
-
|
|
427
|
-
has_one :middle, dependent: :destroy
|
|
428
|
-
has_one :left, through: :middle
|
|
429
|
-
end
|
|
430
|
-
```
|
|
431
|
-
In the above example `left.destroy` wouldn't destroy its associated `Right`
|
|
432
|
-
record.
|
|
441
|
+
* Fix model `filter_attributes` to not add useless filters into `config.filter_parameters`.
|
|
433
442
|
|
|
434
|
-
|
|
443
|
+
Proc and Regexp filters would be improperly turned into string matchers.
|
|
444
|
+
Now they are skipped.
|
|
435
445
|
|
|
436
|
-
*
|
|
446
|
+
*Jonathan Calvert*
|
|
437
447
|
|
|
438
|
-
|
|
448
|
+
* Fix `ActiveRecord::MessagePack` serialization raising `NoMethodError`
|
|
449
|
+
for any record with a populated `time` column, which made such records
|
|
450
|
+
uncacheable through the MessagePack cache serializer.
|
|
439
451
|
|
|
440
|
-
|
|
441
|
-
such as capybara, it could happen that a connection end up pinned by the
|
|
442
|
-
server thread rather than the test thread, causing
|
|
443
|
-
`"Cannot expire connection, it is owned by a different thread"` errors.
|
|
452
|
+
*Kenta Ishizaki*
|
|
444
453
|
|
|
445
|
-
|
|
454
|
+
* Fix replacing or clearing a polymorphic `has_one` leaving a stale type column
|
|
455
|
+
on the removed record.
|
|
446
456
|
|
|
447
|
-
*
|
|
457
|
+
*Kenta Ishizaki*
|
|
448
458
|
|
|
449
|
-
|
|
459
|
+
* Fix `accepts_nested_attributes_for` `:limit` miscounting a single-record hash.
|
|
450
460
|
|
|
451
|
-
|
|
452
|
-
User.with(foo: [User.select(:id), User.select(:id), User.select(:id)]).to_sql
|
|
453
|
-
undefined method `union' for an instance of Arel::Nodes::UnionAll (NoMethodError)
|
|
454
|
-
```
|
|
461
|
+
*Kenta Ishizaki*
|
|
455
462
|
|
|
456
|
-
|
|
463
|
+
* Fix `rename_index` to preserve a partial index's `WHERE` for SQLite and older MySQL/MariaDB versions.
|
|
457
464
|
|
|
458
|
-
*
|
|
465
|
+
*Kenta Ishizaki*
|
|
459
466
|
|
|
460
|
-
*
|
|
467
|
+
* Fix PostgreSQL `foreign_keys` returning a corrupted `to_table` for a foreign key
|
|
468
|
+
that references a table in a quoted schema.
|
|
461
469
|
|
|
462
|
-
|
|
470
|
+
*Kenta Ishizaki*
|
|
463
471
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
causing "Cannot expire connection, it is owned by a different thread" errors in later tests.
|
|
472
|
+
* Fix grouped calculations (e.g. `count`) grouped by a `belongs_to` association
|
|
473
|
+
that points to a composite primary key model.
|
|
467
474
|
|
|
468
|
-
|
|
475
|
+
`Book.group(:order).count`, where `Book belongs_to :order` and `Order` has a
|
|
476
|
+
composite primary key, raised `ArgumentError: Expected corresponding value
|
|
477
|
+
for ["shop_id", "id"] to be an Array`. The grouped result is now keyed by the
|
|
478
|
+
associated records as it already is for single-column keys.
|
|
469
479
|
|
|
470
|
-
*
|
|
480
|
+
*Kenta Ishizaki*
|
|
471
481
|
|
|
472
|
-
|
|
482
|
+
* Fix `has_many`/`has_one :through` associations with `disable_joins: true`
|
|
483
|
+
silently returning an empty result when the source points to a composite
|
|
484
|
+
primary key model.
|
|
473
485
|
|
|
474
|
-
*
|
|
486
|
+
*Kenta Ishizaki*
|
|
475
487
|
|
|
476
|
-
* Fix
|
|
477
|
-
|
|
488
|
+
* Fix collection association `ids=` writers (e.g. `author.book_ids=`) raising
|
|
489
|
+
`ActiveRecord::RecordNotFound` for existing records when a composite primary
|
|
490
|
+
key model is assigned string ids (the shape ids take from request params).
|
|
478
491
|
|
|
479
|
-
|
|
492
|
+
Each id component is now cast against its own column type, instead of casting
|
|
493
|
+
the whole tuple against an array of column names, which `type_for_attribute`
|
|
494
|
+
can't resolve to a real type (so the cast was a no-op and the string ids
|
|
495
|
+
never matched the loaded records).
|
|
480
496
|
|
|
481
|
-
|
|
497
|
+
*Kenta Ishizaki*
|
|
482
498
|
|
|
483
|
-
|
|
499
|
+
* Fix `find` with multiple composite primary key ids passed as strings
|
|
500
|
+
silently returning `[]`.
|
|
484
501
|
|
|
485
|
-
|
|
502
|
+
`Model.find([["1", "10"], ["1", "20"]])` (the shape ids take when they come
|
|
503
|
+
from request parameters) returned an empty array instead of the records and
|
|
504
|
+
without raising `RecordNotFound`. The ids were cast against the array of key
|
|
505
|
+
column names as a whole — which is a no-op — so the string tuples never
|
|
506
|
+
compared equal to the records' integer ids when ordering the result. Each
|
|
507
|
+
component is now cast against its own column type, matching the documented
|
|
508
|
+
coercion already performed for single-column keys.
|
|
486
509
|
|
|
487
|
-
*
|
|
510
|
+
*Kenta Ishizaki*
|
|
488
511
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
`ActiveRecord::Base` was loaded would give incorrect results.
|
|
512
|
+
* Fix PostgreSQL `daterange` / `tsrange` / `tstzrange` schema dump producing
|
|
513
|
+
invalid Ruby.
|
|
492
514
|
|
|
493
|
-
|
|
494
|
-
|
|
515
|
+
The schema dumper used to render range defaults via `Range#inspect`, which
|
|
516
|
+
falls back to `Date#inspect` / `Time#inspect` for the bounds. The resulting
|
|
517
|
+
`schema.rb` literal (for example `default: Mon, 01 Jan 2024..Wed, 01 Jan 2025`)
|
|
518
|
+
raised a `SyntaxError` on `db:schema:load`. The bounds are now rendered via
|
|
519
|
+
the subtype's `type_cast_for_schema`, so date and timestamp range defaults
|
|
520
|
+
round-trip through `schema.rb` like any other column.
|
|
495
521
|
|
|
496
|
-
|
|
497
|
-
`ActiveRecord::Encryption`, thus preserving the original behavior of having its config ready
|
|
498
|
-
before any use of `ActiveRecord::Base`.
|
|
522
|
+
*Kenta Ishizaki*
|
|
499
523
|
|
|
500
|
-
|
|
524
|
+
* Fix deadlock when pool-less connection materializes while fetching database
|
|
525
|
+
server version.
|
|
501
526
|
|
|
502
|
-
*
|
|
503
|
-
their type, scale, limit & precision.
|
|
527
|
+
*Hartley McGuire*
|
|
504
528
|
|
|
505
|
-
|
|
529
|
+
* Fix PostgreSQL range columns corrupting bounds that contain a comma.
|
|
506
530
|
|
|
507
|
-
|
|
531
|
+
`PostgreSQL::OID::Range#extract_bounds` split a range's textual
|
|
532
|
+
representation on the first comma, but PostgreSQL double-quotes any bound
|
|
533
|
+
that itself contains a comma (e.g. a range over a text subtype). A value
|
|
534
|
+
such as `["a,b","c,d")` was therefore split inside the first quoted bound
|
|
535
|
+
and read back with both endpoints corrupted. The split now skips over
|
|
536
|
+
double-quoted segments when locating the separating comma.
|
|
508
537
|
|
|
538
|
+
*Kenta Ishizaki*
|
|
509
539
|
|
|
510
|
-
|
|
540
|
+
* Fix store accessor `*_change` and `saved_change_to_*` reporting a change
|
|
541
|
+
for unchanged keys.
|
|
511
542
|
|
|
512
|
-
|
|
543
|
+
When one key of a `store` column changed, the generated `<key>_change` and
|
|
544
|
+
`saved_change_to_<key>` methods returned a `[value, value]` pair for the
|
|
545
|
+
column's *other* keys too, even though their matching `<key>_changed?` /
|
|
546
|
+
`saved_change_to_<key>?` correctly returned `false` and standard attribute
|
|
547
|
+
`_change` / `saved_change_to_*` methods return `nil` when unchanged. The
|
|
548
|
+
methods now return `nil` unless that specific key actually changed,
|
|
549
|
+
matching their predicate counterparts.
|
|
513
550
|
|
|
551
|
+
*Kenta Ishizaki*
|
|
514
552
|
|
|
515
|
-
|
|
553
|
+
* Reduce number of queries when introspecting MySQL/MariaDB tables.
|
|
516
554
|
|
|
517
|
-
|
|
555
|
+
A fix to support MariaDB function defaults caused the MySQL adapters to
|
|
556
|
+
issue one query per column when introspecting tables.
|
|
518
557
|
|
|
558
|
+
Now it only issue a single extra query per table, and only when using MariaDB.
|
|
519
559
|
|
|
520
|
-
|
|
560
|
+
*Iliana Hadzhiatanasova*
|
|
521
561
|
|
|
522
|
-
*
|
|
562
|
+
* Fully qualify query criterias in `has_and_belongs_to_many` associations.
|
|
523
563
|
|
|
524
|
-
|
|
564
|
+
Ensure that scopes with the same column name but in different tables aren't lost
|
|
565
|
+
when following an HABTM association.
|
|
525
566
|
|
|
526
|
-
*
|
|
567
|
+
*Philip Maina*
|
|
527
568
|
|
|
528
|
-
|
|
569
|
+
* Fix Active Record Pool Reaper thread leak after `Parallelization#shutdown`.
|
|
529
570
|
|
|
530
|
-
|
|
571
|
+
After parallelized test runs, the parent process leaked the Active Record Pool
|
|
572
|
+
Reaper thread, holding open connection pools and file descriptors for up to
|
|
573
|
+
`reaping_frequency` seconds (or indefinitely if never reaped).
|
|
531
574
|
|
|
532
|
-
|
|
575
|
+
Three fixes: `Parallelization#shutdown` now calls `run_cleanup_hooks`;
|
|
576
|
+
Active Record registers a cleanup hook that discards all connection pools; and
|
|
577
|
+
`ConnectionPool#discard!` now calls `Reaper.discard_pool`, which immediately
|
|
578
|
+
kills and joins the reaper thread when no pools remain at that frequency.
|
|
533
579
|
|
|
534
|
-
*
|
|
580
|
+
*Ruy Rocha*
|
|
535
581
|
|
|
536
|
-
|
|
582
|
+
* Fix duplicate `WHERE` conditions in `create_or_find_by`.
|
|
537
583
|
|
|
538
|
-
|
|
584
|
+
When `create_or_find_by` catches a `RecordNotUnique` error and retries the query, it now uses `rewhere` and `take!` to prevent duplicating existing scope conditions.
|
|
539
585
|
|
|
540
|
-
*
|
|
586
|
+
*Yavor Dashev*
|
|
541
587
|
|
|
542
|
-
* Fix `ActiveRecord::
|
|
588
|
+
* Fix `ActiveRecord::QueryMethods#in_order_of` when passing an out-of-range Integer
|
|
543
589
|
|
|
544
|
-
|
|
590
|
+
To match the behavior of the `Enumerable` version, `in_order_of` now ignores an out-of-range Integer.
|
|
545
591
|
|
|
546
|
-
*
|
|
592
|
+
*tejanium*
|
|
547
593
|
|
|
548
|
-
|
|
594
|
+
* Revert alphabetical sorting of table columns inside `schema.rb`.
|
|
549
595
|
|
|
550
|
-
|
|
596
|
+
Alphabetical sorting of table columns inside the schema creates improper production tables when using `db:prepare`.
|
|
551
597
|
|
|
552
|
-
*
|
|
553
|
-
actual cast type.
|
|
598
|
+
*Bert McCutchen*
|
|
554
599
|
|
|
555
|
-
|
|
600
|
+
* Fix `strict_loading` violations ignored when using `pluck`
|
|
556
601
|
|
|
557
|
-
*
|
|
602
|
+
*Johnson Chan*
|
|
558
603
|
|
|
559
|
-
|
|
604
|
+
* Fix incorrect callback execution order when `config.active_record.run_after_transaction_callbacks_in_order_defined = true`
|
|
605
|
+
and using `after_commit` and `after_rollback` callbacks with `prepend: true`.
|
|
560
606
|
|
|
607
|
+
*Joshua Young*
|
|
561
608
|
|
|
562
|
-
|
|
609
|
+
* Fix `becomes` to preserve `marked_for_destruction?`.
|
|
563
610
|
|
|
564
|
-
*
|
|
611
|
+
*Vincent Robert*
|
|
565
612
|
|
|
566
|
-
|
|
613
|
+
* MySQL error 1046 (`ER_NO_DB_ERROR: No database selected`) is now retryable as a `ConnectionFailed` exception
|
|
567
614
|
|
|
568
|
-
*
|
|
569
|
-
singular association and having `index_nested_attribute_errors` enabled.
|
|
615
|
+
*Clay Harmon*
|
|
570
616
|
|
|
571
|
-
*Martin Spickermann*
|
|
572
617
|
|
|
573
|
-
|
|
574
|
-
we want to reserve that name for a stronger sense of "immutable relation".
|
|
575
|
-
Please use `ActiveRecord::UnmodifiableRelation` instead.
|
|
618
|
+
## Rails 8.1.3.1 (July 29, 2026) ##
|
|
576
619
|
|
|
577
|
-
|
|
620
|
+
* No changes.
|
|
578
621
|
|
|
579
|
-
* Add condensed `#inspect` for `ConnectionPool`, `AbstractAdapter`, and
|
|
580
|
-
`DatabaseConfig`.
|
|
581
622
|
|
|
582
|
-
|
|
623
|
+
## Rails 8.1.3 (March 24, 2026) ##
|
|
583
624
|
|
|
584
|
-
*
|
|
625
|
+
* Fix `insert_all` and `upsert_all` log message when called on anonymous classes.
|
|
585
626
|
|
|
586
|
-
*
|
|
627
|
+
*Gabriel Sobrinho*
|
|
587
628
|
|
|
588
|
-
*
|
|
629
|
+
* Respect `ActiveRecord::SchemaDumper.ignore_tables` when dumping SQLite virtual tables.
|
|
589
630
|
|
|
590
|
-
|
|
591
|
-
complements `transaction.active_record`, which is emitted when they finish.
|
|
631
|
+
*Hans Schnedlitz*
|
|
592
632
|
|
|
593
|
-
|
|
633
|
+
* Restore previous instrumenter after `execute_or_skip`
|
|
594
634
|
|
|
595
|
-
|
|
635
|
+
`FutureResult#execute_or_skip` replaces the thread's instrumenter with an
|
|
636
|
+
`EventBuffer` to collect events published during async query execution.
|
|
637
|
+
If the global async executor is saturated and the `caller_runs` fallback
|
|
638
|
+
executes the task on the calling thread, we need to make sure the previous
|
|
639
|
+
instrumenter is restored or the stale `EventBuffer` would stay in place and
|
|
640
|
+
permanently swallow all subsequent `sql.active_record` notifications on
|
|
641
|
+
that thread.
|
|
596
642
|
|
|
597
|
-
*
|
|
598
|
-
for preloaded associations in models using composite primary keys.
|
|
643
|
+
*Rosa Gutierrez*
|
|
599
644
|
|
|
600
|
-
|
|
645
|
+
* Bump the minimum PostgreSQL version to 9.5, due to usage of `array_position` function.
|
|
601
646
|
|
|
602
|
-
*
|
|
647
|
+
*Ivan Kuchin*
|
|
603
648
|
|
|
604
|
-
|
|
649
|
+
* Fix Ruby 4.0 delegator warning when calling inspect on ActiveRecord::Type::Serialized.
|
|
605
650
|
|
|
606
|
-
*
|
|
651
|
+
*Hammad Khan*
|
|
607
652
|
|
|
608
|
-
|
|
653
|
+
* Fix support for table names containing hyphens.
|
|
609
654
|
|
|
610
|
-
*
|
|
655
|
+
*Evgeniy Demin*
|
|
611
656
|
|
|
612
|
-
|
|
657
|
+
* Fix column deduplication for SQLite3 and PostgreSQL virtual (generated) columns.
|
|
613
658
|
|
|
614
|
-
|
|
659
|
+
`Column#==` and `Column#hash` now account for `virtual?` so that the
|
|
660
|
+
`Deduplicable` registry does not treat a generated column and a regular
|
|
661
|
+
column with the same name and type as identical. Previously, if a
|
|
662
|
+
generated column was registered first, a regular column on a different
|
|
663
|
+
table could be deduplicated to the generated instance, silently
|
|
664
|
+
excluding it from INSERT/UPDATE statements.
|
|
615
665
|
|
|
616
|
-
|
|
666
|
+
*Jay Huber*
|
|
617
667
|
|
|
618
|
-
|
|
619
|
-
class Nested::Post < ApplicationRecord
|
|
620
|
-
has_one :post, through: :other
|
|
621
|
-
end
|
|
622
|
-
```
|
|
668
|
+
* Fix PostgreSQL schema dumping to handle schema-qualified table names in foreign_key references that span different schemas.
|
|
623
669
|
|
|
624
|
-
|
|
670
|
+
# before
|
|
671
|
+
add_foreign_key "hst.event_log_attributes", "hst.event_logs" # emits correctly because they're in the same schema (hst)
|
|
672
|
+
add_foreign_key "hst.event_log_attributes", "hst.usr.user_profiles", column: "created_by_id" # emits hst.user.* when user.* is expected
|
|
625
673
|
|
|
626
|
-
|
|
674
|
+
# after
|
|
675
|
+
add_foreign_key "hst.event_log_attributes", "hst.event_logs"
|
|
676
|
+
add_foreign_key "hst.event_log_attributes", "usr.user_profiles", column: "created_by_id"
|
|
627
677
|
|
|
628
|
-
*
|
|
678
|
+
*Chiperific*
|
|
629
679
|
|
|
630
|
-
*Taketo Takashima*
|
|
631
680
|
|
|
632
|
-
|
|
681
|
+
## Rails 8.1.2.1 (March 23, 2026) ##
|
|
633
682
|
|
|
634
|
-
|
|
683
|
+
* No changes.
|
|
635
684
|
|
|
636
|
-
*fatkodima*
|
|
637
685
|
|
|
638
|
-
|
|
686
|
+
## Rails 8.1.2 (January 08, 2026) ##
|
|
639
687
|
|
|
640
|
-
|
|
641
|
-
Post.in_batches.touch_all
|
|
642
|
-
```
|
|
688
|
+
* Fix counting cached queries in `ActiveRecord::RuntimeRegistry`.
|
|
643
689
|
|
|
644
690
|
*fatkodima*
|
|
645
691
|
|
|
646
|
-
*
|
|
692
|
+
* Fix merging relations with arel equality predicates with null relations.
|
|
647
693
|
|
|
648
694
|
*fatkodima*
|
|
649
695
|
|
|
650
|
-
* Fix
|
|
696
|
+
* Fix SQLite3 schema dump for non-autoincrement integer primary keys.
|
|
651
697
|
|
|
652
|
-
|
|
698
|
+
Previously, `schema.rb` should incorrectly restore that table with an auto incrementing
|
|
699
|
+
primary key.
|
|
653
700
|
|
|
654
|
-
*
|
|
701
|
+
*Chris Hasiński*
|
|
655
702
|
|
|
656
|
-
|
|
703
|
+
* Fix PostgreSQL `schema_search_path` not being reapplied after `reset!` or `reconnect!`.
|
|
657
704
|
|
|
658
|
-
|
|
705
|
+
The `schema_search_path` configured in `database.yml` is now correctly
|
|
706
|
+
reapplied instead of falling back to PostgreSQL defaults.
|
|
659
707
|
|
|
660
|
-
*
|
|
708
|
+
*Tobias Egli*
|
|
661
709
|
|
|
662
|
-
|
|
710
|
+
* Restore the ability of enum to be foats.
|
|
663
711
|
|
|
664
|
-
|
|
712
|
+
```ruby
|
|
713
|
+
enum :rating, { low: 0.0, medium: 0.5, high: 1.0 },
|
|
714
|
+
```
|
|
665
715
|
|
|
666
|
-
|
|
716
|
+
In Rails 8.1.0, enum values are eagerly validated, and floats weren't expected.
|
|
667
717
|
|
|
668
|
-
*
|
|
718
|
+
*Said Kaldybaev*
|
|
669
719
|
|
|
670
|
-
|
|
720
|
+
* Ensure batched preloaded associations accounts for klass when grouping to avoid issues with STI.
|
|
671
721
|
|
|
672
|
-
*
|
|
722
|
+
*zzak*, *Stjepan Hadjic*
|
|
673
723
|
|
|
674
|
-
*
|
|
724
|
+
* Fix `ActiveRecord::SoleRecordExceeded#record` to return the relation.
|
|
675
725
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
post_and_replies: [
|
|
679
|
-
Post.where(id: 42),
|
|
680
|
-
Post.joins('JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id'),
|
|
681
|
-
]
|
|
682
|
-
)
|
|
683
|
-
```
|
|
726
|
+
This was the case until Rails 7.2, but starting from 8.0 it
|
|
727
|
+
started mistakenly returning the model class.
|
|
684
728
|
|
|
685
|
-
|
|
729
|
+
*Jean Boussier*
|
|
686
730
|
|
|
687
|
-
|
|
688
|
-
WITH RECURSIVE "post_and_replies" AS (
|
|
689
|
-
(SELECT "posts".* FROM "posts" WHERE "posts"."id" = 42)
|
|
690
|
-
UNION ALL
|
|
691
|
-
(SELECT "posts".* FROM "posts" JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id)
|
|
692
|
-
)
|
|
693
|
-
SELECT "posts".* FROM "posts"
|
|
694
|
-
```
|
|
731
|
+
* Improve PostgreSQLAdapter resilience to Timeout.timeout.
|
|
695
732
|
|
|
696
|
-
|
|
733
|
+
Better handle asynchronous exceptions being thrown inside
|
|
734
|
+
the `reconnect!` method.
|
|
697
735
|
|
|
698
|
-
|
|
736
|
+
This may fixes some deep errors such as:
|
|
699
737
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
t.check_constraint "price > discounted_price", name: "price_check", validate: false
|
|
704
|
-
t.validate_check_constraint "price_check"
|
|
705
|
-
end
|
|
738
|
+
```
|
|
739
|
+
undefined method `key?' for nil:NilClass (NoMethodError)
|
|
740
|
+
if !type_map.key?(oid)
|
|
706
741
|
```
|
|
707
742
|
|
|
708
|
-
*
|
|
743
|
+
*Jean Boussier*
|
|
709
744
|
|
|
710
|
-
*
|
|
745
|
+
* Fix structured events for Active Record was not being emitted.
|
|
711
746
|
|
|
712
|
-
|
|
713
|
-
```ruby
|
|
714
|
-
ActiveRecord::Base.connection
|
|
715
|
-
.select_value("select '2024-01-01'::date").class #=> Date
|
|
716
|
-
```
|
|
747
|
+
*Yuji Yaginuma*
|
|
717
748
|
|
|
718
|
-
|
|
749
|
+
* Fix `eager_load` when loading `has_many` assocations with composite primary keys.
|
|
719
750
|
|
|
720
|
-
|
|
751
|
+
This would result in some records being loaded multiple times.
|
|
721
752
|
|
|
722
|
-
|
|
723
|
-
match intended behavior and to prevent non-deterministic order issues caused
|
|
724
|
-
by calling methods like `first` or `last`. As `first` and `last` don't cause
|
|
725
|
-
an N+1 by themselves, calling child associations will no longer raise.
|
|
726
|
-
Fixes #49473.
|
|
753
|
+
*Martin-Alexander*
|
|
727
754
|
|
|
728
|
-
Before:
|
|
729
755
|
|
|
730
|
-
|
|
731
|
-
person = Person.find(1)
|
|
732
|
-
person.strict_loading!(mode: :n_plus_one_only)
|
|
733
|
-
person.posts.first
|
|
734
|
-
# SELECT * FROM posts WHERE person_id = 1; -- non-deterministic order
|
|
735
|
-
person.posts.first.firm # raises ActiveRecord::StrictLoadingViolationError
|
|
736
|
-
```
|
|
756
|
+
## Rails 8.1.1 (October 28, 2025) ##
|
|
737
757
|
|
|
738
|
-
|
|
758
|
+
* No changes.
|
|
739
759
|
|
|
740
|
-
```ruby
|
|
741
|
-
person = Person.find(1)
|
|
742
|
-
person.strict_loading!(mode: :n_plus_one_only)
|
|
743
|
-
person.posts.first # this is 1+1, not N+1
|
|
744
|
-
# SELECT * FROM posts WHERE person_id = 1 ORDER BY id LIMIT 1;
|
|
745
|
-
person.posts.first.firm # no longer raises
|
|
746
|
-
```
|
|
747
760
|
|
|
748
|
-
|
|
761
|
+
## Rails 8.1.0 (October 22, 2025) ##
|
|
749
762
|
|
|
750
|
-
*
|
|
763
|
+
* Fix SQLite3 data loss during table alterations with CASCADE foreign keys.
|
|
751
764
|
|
|
752
|
-
|
|
765
|
+
When altering a table in SQLite3 that is referenced by child tables with
|
|
766
|
+
`ON DELETE CASCADE` foreign keys, ActiveRecord would silently delete all
|
|
767
|
+
data from the child tables. This occurred because SQLite requires table
|
|
768
|
+
recreation for schema changes, and during this process the original table
|
|
769
|
+
is temporarily dropped, triggering CASCADE deletes on child tables.
|
|
753
770
|
|
|
754
|
-
|
|
771
|
+
The root cause was incorrect ordering of operations. The original code
|
|
772
|
+
wrapped `disable_referential_integrity` inside a transaction, but
|
|
773
|
+
`PRAGMA foreign_keys` cannot be modified inside a transaction in SQLite -
|
|
774
|
+
attempting to do so simply has no effect. This meant foreign keys remained
|
|
775
|
+
enabled during table recreation, causing CASCADE deletes to fire.
|
|
755
776
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
777
|
+
The fix reverses the order to follow the official SQLite 12-step ALTER TABLE
|
|
778
|
+
procedure: `disable_referential_integrity` now wraps the transaction instead
|
|
779
|
+
of being wrapped by it. This ensures foreign keys are properly disabled
|
|
780
|
+
before the transaction starts and re-enabled after it commits, preventing
|
|
781
|
+
CASCADE deletes while maintaining data integrity through atomic transactions.
|
|
759
782
|
|
|
760
|
-
|
|
761
|
-
Post.joins(:comments).pluck(posts: [:id], comments: [:id, :body])
|
|
762
|
-
```
|
|
783
|
+
*Ruy Rocha*
|
|
763
784
|
|
|
764
|
-
|
|
785
|
+
* Add replicas to test database parallelization setup.
|
|
765
786
|
|
|
766
|
-
|
|
787
|
+
Setup and configuration of databases for parallel testing now includes replicas.
|
|
767
788
|
|
|
768
|
-
|
|
789
|
+
This fixes an issue when using a replica database, database selector middleware,
|
|
790
|
+
and non-transactional tests, where integration tests running in parallel would select
|
|
791
|
+
the base test database, i.e. `db_test`, instead of the numbered parallel worker database,
|
|
792
|
+
i.e. `db_test_{n}`.
|
|
769
793
|
|
|
770
|
-
*
|
|
794
|
+
*Adam Maas*
|
|
771
795
|
|
|
772
|
-
|
|
796
|
+
* Support virtual (not persisted) generated columns on PostgreSQL 18+
|
|
797
|
+
|
|
798
|
+
PostgreSQL 18 introduces virtual (not persisted) generated columns,
|
|
799
|
+
which are now the default unless the `stored: true` option is explicitly specified on PostgreSQL 18+.
|
|
773
800
|
|
|
774
801
|
```ruby
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
end
|
|
802
|
+
create_table :users do |t|
|
|
803
|
+
t.string :name
|
|
804
|
+
t.virtual :lower_name, type: :string, as: "LOWER(name)", stored: false
|
|
805
|
+
t.virtual :name_length, type: :integer, as: "LENGTH(name)"
|
|
780
806
|
end
|
|
781
807
|
```
|
|
782
808
|
|
|
783
|
-
*
|
|
784
|
-
|
|
785
|
-
* Add `ActiveRecord::Base.current_transaction`.
|
|
809
|
+
*Yasuo Honda*
|
|
786
810
|
|
|
787
|
-
|
|
811
|
+
* Optimize schema dumping to prevent duplicate file generation.
|
|
788
812
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
```
|
|
813
|
+
`ActiveRecord::Tasks::DatabaseTasks.dump_all` now tracks which schema files
|
|
814
|
+
have already been dumped and skips dumping the same file multiple times.
|
|
815
|
+
This improves performance when multiple database configurations share the
|
|
816
|
+
same schema dump path.
|
|
794
817
|
|
|
795
|
-
*
|
|
818
|
+
*Mikey Gough*, *Hartley McGuire*
|
|
796
819
|
|
|
797
|
-
* Add
|
|
820
|
+
* Add structured events for Active Record:
|
|
821
|
+
- `active_record.strict_loading_violation`
|
|
822
|
+
- `active_record.sql`
|
|
798
823
|
|
|
799
|
-
|
|
800
|
-
to perform work after the state changes have been properly persisted.
|
|
824
|
+
*Gannon McGibbon*
|
|
801
825
|
|
|
826
|
+
* Add support for integer shard keys.
|
|
802
827
|
```ruby
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
828
|
+
# Now accepts symbols as shard keys.
|
|
829
|
+
ActiveRecord::Base.connects_to(shards: {
|
|
830
|
+
1: { writing: :primary_shard_one, reading: :primary_shard_one },
|
|
831
|
+
2: { writing: :primary_shard_two, reading: :primary_shard_two},
|
|
832
|
+
})
|
|
833
|
+
|
|
834
|
+
ActiveRecord::Base.connected_to(shard: 1) do
|
|
835
|
+
# ..
|
|
808
836
|
end
|
|
809
837
|
```
|
|
810
838
|
|
|
811
|
-
|
|
812
|
-
of a transaction, or called after the open transaction is committed.
|
|
839
|
+
*Nony Dutton*
|
|
813
840
|
|
|
814
|
-
|
|
841
|
+
* Add `ActiveRecord::Base.only_columns`
|
|
815
842
|
|
|
816
|
-
|
|
843
|
+
Similar in use case to `ignored_columns` but listing columns to consider rather than the ones
|
|
844
|
+
to ignore.
|
|
817
845
|
|
|
818
|
-
|
|
846
|
+
Can be useful when working with a legacy or shared database schema, or to make safe schema change
|
|
847
|
+
in two deploys rather than three.
|
|
819
848
|
|
|
820
|
-
|
|
821
|
-
values must be backfilled separately of the column addition (to not lock the table for too long)
|
|
822
|
-
and before the use of `:counter_cache` (otherwise methods like `size`/`any?`/etc, which use
|
|
823
|
-
counter caches internally, can produce incorrect results). People usually use database triggers
|
|
824
|
-
or callbacks on child associations while backfilling before introducing a counter cache
|
|
825
|
-
configuration to the association.
|
|
849
|
+
*Anton Kandratski*
|
|
826
850
|
|
|
827
|
-
|
|
851
|
+
* Use `PG::Connection#close_prepared` (protocol level Close) to deallocate
|
|
852
|
+
prepared statements when available.
|
|
828
853
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
belongs_to :post, counter_cache: { active: false }
|
|
832
|
-
end
|
|
833
|
-
```
|
|
854
|
+
To enable its use, you must have pg >= 1.6.0, libpq >= 17, and a PostgreSQL
|
|
855
|
+
database version >= 17.
|
|
834
856
|
|
|
835
|
-
|
|
836
|
-
but get the results directly from the database. After the counter cache column is backfilled, simply
|
|
837
|
-
remove the `{ active: false }` part from the counter cache definition, and it will now be used by the
|
|
838
|
-
mentioned methods.
|
|
857
|
+
*Hartley McGuire*, *Andrew Jackson*
|
|
839
858
|
|
|
840
|
-
|
|
859
|
+
* Fix query cache for pinned connections in multi threaded transactional tests
|
|
841
860
|
|
|
842
|
-
|
|
861
|
+
When a pinned connection is used across separate threads, they now use a separate cache store
|
|
862
|
+
for each thread.
|
|
843
863
|
|
|
844
|
-
|
|
845
|
-
are idempotent and can safely be retried in the case of a connection error. Previously,
|
|
846
|
-
adapters such as `TrilogyAdapter` would raise `ActiveRecord::ConnectionFailed: Trilogy::EOFError`
|
|
847
|
-
when encountering a connection error mid-request.
|
|
864
|
+
This improve accuracy of system tests, and any test using multiple threads.
|
|
848
865
|
|
|
849
|
-
*
|
|
866
|
+
*Heinrich Lee Yu*, *Jean Boussier*
|
|
850
867
|
|
|
851
|
-
*
|
|
868
|
+
* Fix time attribute dirty tracking with timezone conversions.
|
|
852
869
|
|
|
853
|
-
|
|
854
|
-
|
|
870
|
+
Time-only attributes now maintain a fixed date of 2000-01-01 during timezone conversions,
|
|
871
|
+
preventing them from being incorrectly marked as changed due to date shifts.
|
|
855
872
|
|
|
856
|
-
|
|
873
|
+
This fixes an issue where time attributes would be marked as changed when setting the same time value
|
|
874
|
+
due to timezone conversion causing internal date shifts.
|
|
857
875
|
|
|
858
|
-
*
|
|
876
|
+
*Prateek Choudhary*
|
|
859
877
|
|
|
860
|
-
|
|
861
|
-
|
|
878
|
+
* Skip calling `PG::Connection#cancel` in `cancel_any_running_query`
|
|
879
|
+
when using libpq >= 18 with pg < 1.6.0, due to incompatibility.
|
|
880
|
+
Rollback still runs, but may take longer.
|
|
862
881
|
|
|
863
|
-
*
|
|
882
|
+
*Yasuo Honda*, *Lars Kanis*
|
|
864
883
|
|
|
865
|
-
*
|
|
884
|
+
* Don't add `id_value` attribute alias when attribute/column with that name already exists.
|
|
866
885
|
|
|
867
|
-
|
|
886
|
+
*Rob Lewis*
|
|
868
887
|
|
|
869
|
-
|
|
870
|
-
the request or job. This behavior can be undesirable in environments that use many more threads or fibers than there
|
|
871
|
-
is available connections.
|
|
888
|
+
* Remove deprecated `:unsigned_float` and `:unsigned_decimal` column methods for MySQL.
|
|
872
889
|
|
|
873
|
-
|
|
874
|
-
migrate it to use `ActiveRecord::Base.with_connection` instead.
|
|
890
|
+
*Rafael Mendonça França*
|
|
875
891
|
|
|
876
|
-
|
|
892
|
+
* Remove deprecated `:retries` option for the SQLite3 adapter.
|
|
877
893
|
|
|
878
|
-
*
|
|
894
|
+
*Rafael Mendonça França*
|
|
895
|
+
|
|
896
|
+
* Introduce new database configuration options `keepalive`, `max_age`, and
|
|
897
|
+
`min_connections` -- and rename `pool` to `max_connections` to match.
|
|
879
898
|
|
|
880
|
-
|
|
899
|
+
There are no changes to default behavior, but these allow for more specific
|
|
900
|
+
control over pool behavior.
|
|
881
901
|
|
|
882
|
-
|
|
883
|
-
`ActiveRecord::ConnectionAdapters::ConnectionPool#uncached`.
|
|
902
|
+
*Matthew Draper*, *Chris AtLee*, *Rachael Wright-Munn*
|
|
884
903
|
|
|
885
|
-
|
|
886
|
-
When set to `false`, writes to the affected connection pool will not clear any query cache.
|
|
904
|
+
* Move `LIMIT` validation from query generation to when `limit()` is called.
|
|
887
905
|
|
|
888
|
-
|
|
906
|
+
*Hartley McGuire*, *Shuyang*
|
|
889
907
|
|
|
890
|
-
|
|
908
|
+
* Add `ActiveRecord::CheckViolation` error class for check constraint violations.
|
|
891
909
|
|
|
892
|
-
*
|
|
910
|
+
*Ryuta Kamizono*
|
|
893
911
|
|
|
894
|
-
|
|
895
|
-
connection will be held for the duration of the request or job.
|
|
912
|
+
* Add `ActiveRecord::ExclusionViolation` error class for exclusion constraint violations.
|
|
896
913
|
|
|
897
|
-
|
|
898
|
-
|
|
914
|
+
When an exclusion constraint is violated in PostgreSQL, the error will now be raised
|
|
915
|
+
as `ActiveRecord::ExclusionViolation` instead of the generic `ActiveRecord::StatementInvalid`,
|
|
916
|
+
making it easier to handle these specific constraint violations in application code.
|
|
899
917
|
|
|
900
|
-
|
|
918
|
+
This follows the same pattern as other constraint violation error classes like
|
|
919
|
+
`RecordNotUnique` for unique constraint violations and `InvalidForeignKey` for
|
|
920
|
+
foreign key constraint violations.
|
|
901
921
|
|
|
902
|
-
*
|
|
922
|
+
*Ryuta Kamizono*
|
|
903
923
|
|
|
904
|
-
|
|
905
|
-
|
|
924
|
+
* Attributes filtered by `filter_attributes` will now also be filtered by `filter_parameters`
|
|
925
|
+
so sensitive information is not leaked.
|
|
906
926
|
|
|
907
|
-
*
|
|
927
|
+
*Jill Klang*
|
|
908
928
|
|
|
909
|
-
*
|
|
929
|
+
* Add `connection.current_transaction.isolation` API to check current transaction's isolation level.
|
|
930
|
+
|
|
931
|
+
Returns the isolation level if it was explicitly set via the `isolation:` parameter
|
|
932
|
+
or through `ActiveRecord.with_transaction_isolation_level`, otherwise returns `nil`.
|
|
933
|
+
Nested transactions return the parent transaction's isolation level.
|
|
910
934
|
|
|
911
935
|
```ruby
|
|
912
|
-
|
|
913
|
-
|
|
936
|
+
# Returns nil when no transaction
|
|
937
|
+
User.connection.current_transaction.isolation # => nil
|
|
938
|
+
|
|
939
|
+
# Returns explicitly set isolation level
|
|
940
|
+
User.transaction(isolation: :serializable) do
|
|
941
|
+
User.connection.current_transaction.isolation # => :serializable
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
# Returns nil when isolation not explicitly set
|
|
945
|
+
User.transaction do
|
|
946
|
+
User.connection.current_transaction.isolation # => nil
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
# Nested transactions inherit parent's isolation
|
|
950
|
+
User.transaction(isolation: :read_committed) do
|
|
951
|
+
User.transaction do
|
|
952
|
+
User.connection.current_transaction.isolation # => :read_committed
|
|
953
|
+
end
|
|
954
|
+
end
|
|
914
955
|
```
|
|
915
956
|
|
|
916
|
-
*
|
|
957
|
+
*Kir Shatrov*
|
|
917
958
|
|
|
918
|
-
*
|
|
919
|
-
incorrect error message.
|
|
959
|
+
* Fix `#merge` with `#or` or `#and` and a mixture of attributes and SQL strings resulting in an incorrect query.
|
|
920
960
|
|
|
921
|
-
|
|
961
|
+
```ruby
|
|
962
|
+
base = Comment.joins(:post).where(user_id: 1).where("recent = 1")
|
|
963
|
+
puts base.merge(base.where(draft: true).or(Post.where(archived: true))).to_sql
|
|
964
|
+
```
|
|
922
965
|
|
|
923
|
-
|
|
966
|
+
Before:
|
|
924
967
|
|
|
925
|
-
|
|
968
|
+
```SQL
|
|
969
|
+
SELECT "comments".* FROM "comments"
|
|
970
|
+
INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
|
|
971
|
+
WHERE (recent = 1)
|
|
972
|
+
AND (
|
|
973
|
+
"comments"."user_id" = 1
|
|
974
|
+
AND (recent = 1)
|
|
975
|
+
AND "comments"."draft" = 1
|
|
976
|
+
OR "posts"."archived" = 1
|
|
977
|
+
)
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
After:
|
|
926
981
|
|
|
927
|
-
|
|
928
|
-
|
|
982
|
+
```SQL
|
|
983
|
+
SELECT "comments".* FROM "comments"
|
|
984
|
+
INNER JOIN "posts" ON "posts"."id" = "comments"."post_id"
|
|
985
|
+
WHERE "comments"."user_id" = 1
|
|
986
|
+
AND (recent = 1)
|
|
987
|
+
AND (
|
|
988
|
+
"comments"."user_id" = 1
|
|
989
|
+
AND (recent = 1)
|
|
990
|
+
AND "comments"."draft" = 1
|
|
991
|
+
OR "posts"."archived" = 1
|
|
992
|
+
)
|
|
993
|
+
```
|
|
929
994
|
|
|
930
995
|
*Joshua Young*
|
|
931
996
|
|
|
932
|
-
*
|
|
997
|
+
* Make schema dumper to account for `ActiveRecord.dump_schemas` when dumping in `:ruby` format.
|
|
933
998
|
|
|
934
|
-
*
|
|
999
|
+
*fatkodima*
|
|
935
1000
|
|
|
936
|
-
*
|
|
1001
|
+
* Add `:touch` option to `update_column`/`update_columns` methods.
|
|
937
1002
|
|
|
938
|
-
|
|
1003
|
+
```ruby
|
|
1004
|
+
# Will update :updated_at/:updated_on alongside :nice column.
|
|
1005
|
+
user.update_column(:nice, true, touch: true)
|
|
939
1006
|
|
|
940
|
-
|
|
1007
|
+
# Will update :updated_at/:updated_on alongside :last_ip column
|
|
1008
|
+
user.update_columns(last_ip: request.remote_ip, touch: true)
|
|
1009
|
+
```
|
|
941
1010
|
|
|
942
|
-
*
|
|
1011
|
+
*Dmitrii Ivliev*
|
|
943
1012
|
|
|
944
|
-
*
|
|
1013
|
+
* Optimize Active Record batching further when using ranges.
|
|
945
1014
|
|
|
946
|
-
|
|
1015
|
+
Tested on a PostgreSQL table with 10M records and batches of 10k records, the generation
|
|
1016
|
+
of relations for the 1000 batches was `4.8x` faster (`6.8s` vs. `1.4s`), used `900x`
|
|
1017
|
+
less bandwidth (`180MB` vs. `0.2MB`) and allocated `45x` less memory (`490MB` vs. `11MB`).
|
|
947
1018
|
|
|
948
|
-
*
|
|
1019
|
+
*Maxime Réty*, *fatkodima*
|
|
949
1020
|
|
|
950
|
-
|
|
1021
|
+
* Include current character length in error messages for index and table name length validations.
|
|
951
1022
|
|
|
952
|
-
*
|
|
1023
|
+
*Joshua Young*
|
|
953
1024
|
|
|
954
|
-
|
|
1025
|
+
* Add `rename_schema` method for PostgreSQL.
|
|
955
1026
|
|
|
956
|
-
*
|
|
1027
|
+
*T S Vallender*
|
|
957
1028
|
|
|
958
|
-
|
|
1029
|
+
* Implement support for deprecating associations:
|
|
959
1030
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1031
|
+
```ruby
|
|
1032
|
+
has_many :posts, deprecated: true
|
|
1033
|
+
```
|
|
963
1034
|
|
|
964
|
-
|
|
1035
|
+
With that, Active Record will report any usage of the `posts` association.
|
|
965
1036
|
|
|
966
|
-
|
|
1037
|
+
Three reporting modes are supported (`:warn`, `:raise`, and `:notify`), and
|
|
1038
|
+
backtraces can be enabled or disabled. Defaults are `:warn` mode and
|
|
1039
|
+
disabled backtraces.
|
|
967
1040
|
|
|
968
|
-
|
|
1041
|
+
Please, check the docs for further details.
|
|
969
1042
|
|
|
970
|
-
*
|
|
1043
|
+
*Xavier Noria*
|
|
971
1044
|
|
|
972
|
-
|
|
1045
|
+
* PostgreSQL adapter create DB now supports `locale_provider` and `locale`.
|
|
973
1046
|
|
|
974
|
-
*
|
|
1047
|
+
*Bengt-Ove Hollaender*
|
|
975
1048
|
|
|
976
|
-
|
|
1049
|
+
* Use ntuples to populate row_count instead of count for Postgres
|
|
977
1050
|
|
|
978
|
-
*
|
|
1051
|
+
*Jonathan Calvert*
|
|
979
1052
|
|
|
980
|
-
|
|
1053
|
+
* Fix checking whether an unpersisted record is `include?`d in a strictly
|
|
1054
|
+
loaded `has_and_belongs_to_many` association.
|
|
981
1055
|
|
|
982
|
-
*
|
|
1056
|
+
*Hartley McGuire*
|
|
983
1057
|
|
|
984
|
-
|
|
1058
|
+
* Add ability to change transaction isolation for all pools within a block.
|
|
985
1059
|
|
|
986
|
-
|
|
1060
|
+
This functionality is useful if your application needs to change the database
|
|
1061
|
+
transaction isolation for a request or action.
|
|
987
1062
|
|
|
988
|
-
|
|
1063
|
+
Calling `ActiveRecord.with_transaction_isolation_level(level) {}` in an around filter or
|
|
1064
|
+
middleware will set the transaction isolation for all pools accessed within the block,
|
|
1065
|
+
but not for the pools that aren't.
|
|
989
1066
|
|
|
990
|
-
|
|
1067
|
+
This works with explicit and implicit transactions:
|
|
991
1068
|
|
|
992
|
-
|
|
1069
|
+
```ruby
|
|
1070
|
+
ActiveRecord.with_transaction_isolation_level(:read_committed) do
|
|
1071
|
+
Tag.transaction do # opens a transaction explicitly
|
|
1072
|
+
Tag.create!
|
|
1073
|
+
end
|
|
1074
|
+
end
|
|
1075
|
+
```
|
|
993
1076
|
|
|
994
|
-
|
|
1077
|
+
```ruby
|
|
1078
|
+
ActiveRecord.with_transaction_isolation_level(:read_committed) do
|
|
1079
|
+
Tag.create! # opens a transaction implicitly
|
|
1080
|
+
end
|
|
1081
|
+
```
|
|
995
1082
|
|
|
996
|
-
*
|
|
1083
|
+
*Eileen M. Uchitelle*
|
|
997
1084
|
|
|
998
|
-
*
|
|
1085
|
+
* Raise `ActiveRecord::MissingRequiredOrderError` when order dependent finder methods (e.g. `#first`, `#last`) are
|
|
1086
|
+
called without `order` values on the relation, and the model does not have any order columns (`implicit_order_column`,
|
|
1087
|
+
`query_constraints`, or `primary_key`) to fall back on.
|
|
999
1088
|
|
|
1000
|
-
|
|
1089
|
+
This change will be introduced with a new framework default for Rails 8.1, and the current behavior of not raising
|
|
1090
|
+
an error has been deprecated with the aim of removing the configuration option in Rails 8.2.
|
|
1001
1091
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1092
|
+
```ruby
|
|
1093
|
+
config.active_record.raise_on_missing_required_finder_order_columns = true
|
|
1094
|
+
```
|
|
1004
1095
|
|
|
1005
|
-
*
|
|
1096
|
+
*Joshua Young*
|
|
1006
1097
|
|
|
1007
|
-
*
|
|
1098
|
+
* `:class_name` is now invalid in polymorphic `belongs_to` associations.
|
|
1008
1099
|
|
|
1009
|
-
|
|
1100
|
+
Reason is `:class_name` does not make sense in those associations because
|
|
1101
|
+
the class name of target records is dynamic and stored in the type column.
|
|
1010
1102
|
|
|
1011
|
-
|
|
1103
|
+
Existing polymorphic associations setting this option can just delete it.
|
|
1104
|
+
While it did not raise, it had no effect anyway.
|
|
1012
1105
|
|
|
1013
|
-
*
|
|
1106
|
+
*Xavier Noria*
|
|
1014
1107
|
|
|
1015
|
-
*
|
|
1108
|
+
* Add support for multiple databases to `db:migrate:reset`.
|
|
1016
1109
|
|
|
1017
|
-
*
|
|
1110
|
+
*Joé Dupuis*
|
|
1018
1111
|
|
|
1019
|
-
*
|
|
1112
|
+
* Add `affected_rows` to `ActiveRecord::Result`.
|
|
1020
1113
|
|
|
1021
|
-
*
|
|
1114
|
+
*Jenny Shen*
|
|
1022
1115
|
|
|
1023
|
-
*
|
|
1116
|
+
* Enable passing retryable SqlLiterals to `#where`.
|
|
1024
1117
|
|
|
1025
|
-
*
|
|
1118
|
+
*Hartley McGuire*
|
|
1026
1119
|
|
|
1027
|
-
*
|
|
1120
|
+
* Set default for primary keys in `insert_all`/`upsert_all`.
|
|
1028
1121
|
|
|
1029
|
-
|
|
1122
|
+
Previously in Postgres, updating and inserting new records in one upsert wasn't possible
|
|
1123
|
+
due to null primary key values. `nil` primary key values passed into `insert_all`/`upsert_all`
|
|
1124
|
+
are now implicitly set to the default insert value specified by adapter.
|
|
1030
1125
|
|
|
1031
|
-
*
|
|
1126
|
+
*Jenny Shen*
|
|
1032
1127
|
|
|
1033
|
-
|
|
1128
|
+
* Add a load hook `active_record_database_configurations` for `ActiveRecord::DatabaseConfigurations`
|
|
1034
1129
|
|
|
1035
|
-
*
|
|
1130
|
+
*Mike Dalessio*
|
|
1036
1131
|
|
|
1037
|
-
|
|
1132
|
+
* Use `TRUE` and `FALSE` for SQLite queries with boolean columns.
|
|
1038
1133
|
|
|
1039
|
-
*
|
|
1134
|
+
*Hartley McGuire*
|
|
1040
1135
|
|
|
1041
|
-
|
|
1136
|
+
* Bump minimum supported SQLite to 3.23.0.
|
|
1042
1137
|
|
|
1043
|
-
*
|
|
1138
|
+
*Hartley McGuire*
|
|
1044
1139
|
|
|
1045
|
-
|
|
1140
|
+
* Allow allocated Active Records to lookup associations.
|
|
1046
1141
|
|
|
1047
|
-
|
|
1142
|
+
Previously, the association cache isn't setup on allocated record objects, so association
|
|
1143
|
+
lookups will crash. Test frameworks like mocha use allocate to check for stubbable instance
|
|
1144
|
+
methods, which can trigger an association lookup.
|
|
1048
1145
|
|
|
1049
|
-
*
|
|
1146
|
+
*Gannon McGibbon*
|
|
1050
1147
|
|
|
1051
|
-
*
|
|
1148
|
+
* Encryption now supports `support_unencrypted_data: true` being set per-attribute.
|
|
1052
1149
|
|
|
1053
|
-
|
|
1150
|
+
Previously this only worked if `ActiveRecord::Encryption.config.support_unencrypted_data == true`.
|
|
1151
|
+
Now, if the global config is turned off, you can still opt in for a specific attribute.
|
|
1054
1152
|
|
|
1055
|
-
|
|
1153
|
+
```ruby
|
|
1154
|
+
# ActiveRecord::Encryption.config.support_unencrypted_data = true
|
|
1155
|
+
class User < ActiveRecord::Base
|
|
1156
|
+
encrypts :name, support_unencrypted_data: false # only supports encrypted data
|
|
1157
|
+
encrypts :email # supports encrypted or unencrypted data
|
|
1158
|
+
end
|
|
1159
|
+
```
|
|
1056
1160
|
|
|
1057
|
-
|
|
1161
|
+
```ruby
|
|
1162
|
+
# ActiveRecord::Encryption.config.support_unencrypted_data = false
|
|
1163
|
+
class User < ActiveRecord::Base
|
|
1164
|
+
encrypts :name, support_unencrypted_data: true # supports encrypted or unencrypted data
|
|
1165
|
+
encrypts :email # only supports encrypted data
|
|
1166
|
+
end
|
|
1167
|
+
```
|
|
1058
1168
|
|
|
1059
|
-
*
|
|
1169
|
+
*Alex Ghiculescu*
|
|
1060
1170
|
|
|
1061
|
-
|
|
1171
|
+
* Model generator no longer needs a database connection to validate column types.
|
|
1062
1172
|
|
|
1063
|
-
|
|
1064
|
-
used by the default serializer.
|
|
1173
|
+
*Mike Dalessio*
|
|
1065
1174
|
|
|
1066
|
-
|
|
1175
|
+
* Allow signed ID verifiers to be configurable via `Rails.application.message_verifiers`
|
|
1067
1176
|
|
|
1068
|
-
|
|
1177
|
+
Prior to this change, the primary way to configure signed ID verifiers was
|
|
1178
|
+
to set `signed_id_verifier` on each model class:
|
|
1069
1179
|
|
|
1070
|
-
|
|
1180
|
+
```ruby
|
|
1181
|
+
Post.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
|
|
1182
|
+
Comment.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
|
|
1183
|
+
```
|
|
1071
1184
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1185
|
+
And if the developer did not set `signed_id_verifier`, a verifier would be
|
|
1186
|
+
instantiated with a secret derived from `secret_key_base` and the following
|
|
1187
|
+
options:
|
|
1074
1188
|
|
|
1075
|
-
|
|
1189
|
+
```ruby
|
|
1190
|
+
{ digest: "SHA256", serializer: JSON, url_safe: true }
|
|
1191
|
+
```
|
|
1076
1192
|
|
|
1077
|
-
|
|
1193
|
+
Thus it was cumbersome to rotate configuration for all verifiers.
|
|
1078
1194
|
|
|
1079
|
-
|
|
1195
|
+
This change defines a new Rails config: [`config.active_record.use_legacy_signed_id_verifier`][].
|
|
1196
|
+
The default value is `:generate_and_verify`, which preserves the previous
|
|
1197
|
+
behavior. However, when set to `:verify`, signed ID verifiers will use
|
|
1198
|
+
configuration from `Rails.application.message_verifiers` (specifically,
|
|
1199
|
+
`Rails.application.message_verifiers["active_record/signed_id"]`) to
|
|
1200
|
+
generate and verify signed IDs, but will also verify signed IDs using the
|
|
1201
|
+
older configuration.
|
|
1080
1202
|
|
|
1081
|
-
|
|
1203
|
+
To avoid complication, the new behavior only applies when `signed_id_verifier_secret`
|
|
1204
|
+
is not set on a model class or any of its ancestors. Additionally,
|
|
1205
|
+
`signed_id_verifier_secret` is now deprecated. If you are currently setting
|
|
1206
|
+
`signed_id_verifier_secret` on a model class, you can set `signed_id_verifier`
|
|
1207
|
+
instead:
|
|
1082
1208
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1209
|
+
```ruby
|
|
1210
|
+
# BEFORE
|
|
1211
|
+
Post.signed_id_verifier_secret = "my secret"
|
|
1085
1212
|
|
|
1086
|
-
|
|
1087
|
-
|
|
1213
|
+
# AFTER
|
|
1214
|
+
Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("my secret", digest: "SHA256", serializer: JSON, url_safe: true)
|
|
1215
|
+
```
|
|
1088
1216
|
|
|
1089
|
-
|
|
1217
|
+
To ease migration, `signed_id_verifier` has also been changed to behave as a
|
|
1218
|
+
`class_attribute` (i.e. inheritable), but _only when `signed_id_verifier_secret`
|
|
1219
|
+
is not set_:
|
|
1090
1220
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1221
|
+
```ruby
|
|
1222
|
+
# BEFORE
|
|
1223
|
+
ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
|
|
1224
|
+
Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
|
|
1093
1225
|
|
|
1094
|
-
|
|
1226
|
+
# AFTER
|
|
1227
|
+
ActiveRecord::Base.signed_id_verifier = ActiveSupport::MessageVerifier.new(...)
|
|
1228
|
+
Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => true
|
|
1095
1229
|
|
|
1096
|
-
|
|
1230
|
+
Post.signed_id_verifier_secret = "my secret" # => deprecation warning
|
|
1231
|
+
Post.signed_id_verifier == ActiveRecord::Base.signed_id_verifier # => false
|
|
1232
|
+
```
|
|
1097
1233
|
|
|
1098
|
-
|
|
1234
|
+
Note, however, that it is recommended to eventually migrate from
|
|
1235
|
+
model-specific verifiers to a unified configuration managed by
|
|
1236
|
+
`Rails.application.message_verifiers`. `ActiveSupport::MessageVerifier#rotate`
|
|
1237
|
+
can facilitate that transition. For example:
|
|
1099
1238
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1239
|
+
```ruby
|
|
1240
|
+
# BEFORE
|
|
1241
|
+
# Generate and verify signed Post IDs using Post-specific configuration
|
|
1242
|
+
Post.signed_id_verifier = ActiveSupport::MessageVerifier.new("post secret", ...)
|
|
1103
1243
|
|
|
1104
|
-
|
|
1244
|
+
# AFTER
|
|
1245
|
+
# Generate and verify signed Post IDs using the unified configuration
|
|
1246
|
+
Post.signed_id_verifier = Post.signed_id_verifier.dup
|
|
1247
|
+
# Fall back to Post-specific configuration when verifying signed IDs
|
|
1248
|
+
Post.signed_id_verifier.rotate("post secret", ...)
|
|
1249
|
+
```
|
|
1105
1250
|
|
|
1106
|
-
|
|
1251
|
+
[`config.active_record.use_legacy_signed_id_verifier`]: https://guides.rubyonrails.org/v8.1/configuring.html#config-active-record-use-legacy-signed-id-verifier
|
|
1107
1252
|
|
|
1108
|
-
*
|
|
1109
|
-
of Active Record models, when an application is eager loaded. As a result, encrypted attributes
|
|
1110
|
-
could be misconfigured in some cases.
|
|
1253
|
+
*Ali Sepehri*, *Jonathan Hefner*
|
|
1111
1254
|
|
|
1112
|
-
|
|
1255
|
+
* Prepend `extra_flags` in postgres' `structure_load`
|
|
1113
1256
|
|
|
1114
|
-
|
|
1257
|
+
When specifying `structure_load_flags` with a postgres adapter, the flags
|
|
1258
|
+
were appended to the default flags, instead of prepended.
|
|
1259
|
+
This caused issues with flags not being taken into account by postgres.
|
|
1115
1260
|
|
|
1116
|
-
|
|
1117
|
-
class Function > ApplicationRecord
|
|
1118
|
-
# BAD
|
|
1119
|
-
enum color: [:red, :blue],
|
|
1120
|
-
type: [:instance, :class]
|
|
1121
|
-
|
|
1122
|
-
# GOOD
|
|
1123
|
-
enum :color, [:red, :blue]
|
|
1124
|
-
enum :type, [:instance, :class]
|
|
1125
|
-
end
|
|
1126
|
-
```
|
|
1261
|
+
*Alice Loeser*
|
|
1127
1262
|
|
|
1128
|
-
|
|
1263
|
+
* Allow bypassing primary key/constraint addition in `implicit_order_column`
|
|
1129
1264
|
|
|
1130
|
-
|
|
1265
|
+
When specifying multiple columns in an array for `implicit_order_column`, adding
|
|
1266
|
+
`nil` as the last element will prevent appending the primary key to order
|
|
1267
|
+
conditions. This allows more precise control of indexes used by
|
|
1268
|
+
generated queries. It should be noted that this feature does introduce the risk
|
|
1269
|
+
of API misbehavior if the specified columns are not fully unique.
|
|
1131
1270
|
|
|
1132
|
-
|
|
1133
|
-
the timestamp associated with the current time. This is designed to prevent migrations prefixes
|
|
1134
|
-
from being hand-edited to future timestamps, which impacts migration generation and other
|
|
1135
|
-
migration commands.
|
|
1271
|
+
*Issy Long*
|
|
1136
1272
|
|
|
1137
|
-
|
|
1273
|
+
* Allow setting the `schema_format` via database configuration.
|
|
1138
1274
|
|
|
1139
|
-
|
|
1275
|
+
```
|
|
1276
|
+
primary:
|
|
1277
|
+
schema_format: ruby
|
|
1278
|
+
```
|
|
1140
1279
|
|
|
1141
|
-
|
|
1280
|
+
Useful for multi-database setups when apps require different formats per-database.
|
|
1142
1281
|
|
|
1143
|
-
|
|
1144
|
-
threads, but is required when running transactional tests or system tests
|
|
1145
|
-
and could lead to a SEGV.
|
|
1282
|
+
*T S Vallender*
|
|
1146
1283
|
|
|
1147
|
-
|
|
1284
|
+
* Support disabling indexes for MySQL v8.0.0+ and MariaDB v10.6.0+
|
|
1285
|
+
|
|
1286
|
+
MySQL 8.0.0 added an option to disable indexes from being used by the query
|
|
1287
|
+
optimizer by making them "invisible". This allows the index to still be maintained
|
|
1288
|
+
and updated but no queries will be permitted to use it. This can be useful for adding
|
|
1289
|
+
new invisible indexes or making existing indexes invisible before dropping them
|
|
1290
|
+
to ensure queries are not negatively affected.
|
|
1291
|
+
See https://dev.mysql.com/blog-archive/mysql-8-0-invisible-indexes/ for more details.
|
|
1148
1292
|
|
|
1149
|
-
|
|
1293
|
+
MariaDB 10.6.0 also added support for this feature by allowing indexes to be "ignored"
|
|
1294
|
+
in queries. See https://mariadb.com/kb/en/ignored-indexes/ for more details.
|
|
1295
|
+
|
|
1296
|
+
Active Record now supports this option for MySQL 8.0.0+ and MariaDB 10.6.0+ for
|
|
1297
|
+
index creation and alteration where the new index option `enabled: true/false` can be
|
|
1298
|
+
passed to column and index methods as below:
|
|
1150
1299
|
|
|
1151
1300
|
```ruby
|
|
1152
|
-
|
|
1301
|
+
add_index :users, :email, enabled: false
|
|
1302
|
+
enable_index :users, :email
|
|
1303
|
+
add_column :users, :dob, :string, index: { enabled: false }
|
|
1304
|
+
|
|
1305
|
+
change_table :users do |t|
|
|
1306
|
+
t.index :name, enabled: false
|
|
1307
|
+
t.index :dob
|
|
1308
|
+
t.disable_index :dob
|
|
1309
|
+
t.column :username, :string, index: { enabled: false }
|
|
1310
|
+
t.references :account, index: { enabled: false }
|
|
1311
|
+
end
|
|
1312
|
+
|
|
1313
|
+
create_table :users do |t|
|
|
1314
|
+
t.string :name, index: { enabled: false }
|
|
1315
|
+
t.string :email
|
|
1316
|
+
t.index :email, enabled: false
|
|
1317
|
+
end
|
|
1153
1318
|
```
|
|
1154
1319
|
|
|
1155
|
-
|
|
1156
|
-
(note, there is also a `config.active_record.verbose_query_logs` that serves the same purpose)
|
|
1157
|
-
or occasionally on production for debugging purposes.
|
|
1320
|
+
*Merve Taner*
|
|
1158
1321
|
|
|
1159
|
-
|
|
1322
|
+
* Respect `implicit_order_column` in `ActiveRecord::Relation#reverse_order`.
|
|
1160
1323
|
|
|
1161
|
-
*
|
|
1324
|
+
*Joshua Young*
|
|
1162
1325
|
|
|
1163
|
-
|
|
1326
|
+
* Add column types to `ActiveRecord::Result` for SQLite3.
|
|
1164
1327
|
|
|
1165
|
-
|
|
1166
|
-
class User
|
|
1167
|
-
encrypts :name, encryptor: ActiveRecord::Encryption::Encryptor.new(compress: false)
|
|
1168
|
-
end
|
|
1169
|
-
```
|
|
1328
|
+
*Andrew Kane*
|
|
1170
1329
|
|
|
1171
|
-
|
|
1330
|
+
* Raise `ActiveRecord::ReadOnlyError` when pessimistically locking with a readonly role.
|
|
1172
1331
|
|
|
1173
|
-
*
|
|
1332
|
+
*Joshua Young*
|
|
1174
1333
|
|
|
1175
|
-
|
|
1334
|
+
* Fix using the `SQLite3Adapter`'s `dbconsole` method outside of a Rails application.
|
|
1176
1335
|
|
|
1177
|
-
*
|
|
1336
|
+
*Hartley McGuire*
|
|
1178
1337
|
|
|
1179
|
-
*
|
|
1338
|
+
* Fix migrating multiple databases with `ActiveRecord::PendingMigration` action.
|
|
1180
1339
|
|
|
1181
|
-
|
|
1340
|
+
*Gannon McGibbon*
|
|
1182
1341
|
|
|
1183
|
-
|
|
1342
|
+
* Enable automatically retrying idempotent association queries on connection
|
|
1343
|
+
errors.
|
|
1184
1344
|
|
|
1185
|
-
*
|
|
1345
|
+
*Hartley McGuire*
|
|
1186
1346
|
|
|
1187
|
-
*
|
|
1347
|
+
* Add `allow_retry` to `sql.active_record` instrumentation.
|
|
1188
1348
|
|
|
1189
|
-
|
|
1349
|
+
This enables identifying queries which queries are automatically retryable on connection errors.
|
|
1190
1350
|
|
|
1191
|
-
|
|
1351
|
+
*Hartley McGuire*
|
|
1192
1352
|
|
|
1193
|
-
|
|
1353
|
+
* Better support UPDATE with JOIN for Postgresql and SQLite3
|
|
1194
1354
|
|
|
1195
|
-
|
|
1355
|
+
Previously when generating update queries with one or more JOIN clauses,
|
|
1356
|
+
Active Record would use a sub query which would prevent to reference the joined
|
|
1357
|
+
tables in the `SET` clause, for instance:
|
|
1196
1358
|
|
|
1197
|
-
|
|
1359
|
+
```ruby
|
|
1360
|
+
Comment.joins(:post).update_all("title = posts.title")
|
|
1361
|
+
```
|
|
1198
1362
|
|
|
1199
|
-
|
|
1363
|
+
This is now supported as long as the relation doesn't also use a `LIMIT`, `ORDER` or
|
|
1364
|
+
`GROUP BY` clause. This was supported by the MySQL adapter for a long time.
|
|
1200
1365
|
|
|
1201
|
-
|
|
1366
|
+
*Jean Boussier*
|
|
1202
1367
|
|
|
1203
|
-
|
|
1368
|
+
* Introduce a before-fork hook in `ActiveSupport::Testing::Parallelization` to clear existing
|
|
1369
|
+
connections, to avoid fork-safety issues with the mysql2 adapter.
|
|
1204
1370
|
|
|
1205
|
-
|
|
1371
|
+
Fixes #41776
|
|
1206
1372
|
|
|
1207
|
-
*
|
|
1208
|
-
`add_reference` and `t.references`.
|
|
1373
|
+
*Mike Dalessio*, *Donal McBreen*
|
|
1209
1374
|
|
|
1210
|
-
|
|
1375
|
+
* PoolConfig no longer keeps a reference to the connection class.
|
|
1211
1376
|
|
|
1212
|
-
|
|
1377
|
+
Keeping a reference to the class caused subtle issues when combined with reloading in
|
|
1378
|
+
development. Fixes #54343.
|
|
1213
1379
|
|
|
1214
|
-
*
|
|
1380
|
+
*Mike Dalessio*
|
|
1215
1381
|
|
|
1216
|
-
*
|
|
1382
|
+
* Fix SQL notifications sometimes not sent when using async queries.
|
|
1217
1383
|
|
|
1218
|
-
|
|
1384
|
+
```ruby
|
|
1385
|
+
Post.async_count
|
|
1386
|
+
ActiveSupport::Notifications.subscribed(->(*) { "Will never reach here" }) do
|
|
1387
|
+
Post.count
|
|
1388
|
+
end
|
|
1389
|
+
```
|
|
1219
1390
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1391
|
+
In rare circumstances and under the right race condition, Active Support notifications
|
|
1392
|
+
would no longer be dispatched after using an asynchronous query.
|
|
1393
|
+
This is now fixed.
|
|
1222
1394
|
|
|
1223
|
-
*
|
|
1395
|
+
*Edouard Chin*
|
|
1224
1396
|
|
|
1225
|
-
*
|
|
1397
|
+
* Eliminate queries loading dumped schema cache on Postgres
|
|
1226
1398
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1399
|
+
Improve resiliency by avoiding needing to open a database connection to load the
|
|
1400
|
+
type map while defining attribute methods at boot when a schema cache file is
|
|
1401
|
+
configured on PostgreSQL databases.
|
|
1229
1402
|
|
|
1230
|
-
*
|
|
1403
|
+
*James Coleman*
|
|
1231
1404
|
|
|
1232
|
-
*
|
|
1405
|
+
* `ActiveRecord::Coder::JSON` can be instantiated
|
|
1233
1406
|
|
|
1234
|
-
|
|
1407
|
+
Options can now be passed to `ActiveRecord::Coder::JSON` when instantiating the coder. This allows:
|
|
1408
|
+
```ruby
|
|
1409
|
+
serialize :config, coder: ActiveRecord::Coder::JSON.new(symbolize_names: true)
|
|
1410
|
+
```
|
|
1411
|
+
*matthaigh27*
|
|
1235
1412
|
|
|
1236
|
-
|
|
1413
|
+
* Deprecate using `insert_all`/`upsert_all` with unpersisted records in associations.
|
|
1237
1414
|
|
|
1238
|
-
|
|
1415
|
+
Using these methods on associations containing unpersisted records will now
|
|
1416
|
+
show a deprecation warning, as the unpersisted records will be lost after
|
|
1417
|
+
the operation.
|
|
1239
1418
|
|
|
1240
|
-
*
|
|
1419
|
+
*Nick Schwaderer*
|
|
1241
1420
|
|
|
1242
|
-
*
|
|
1421
|
+
* Make column name optional for `index_exists?`.
|
|
1243
1422
|
|
|
1244
|
-
|
|
1423
|
+
This aligns well with `remove_index` signature as well, where
|
|
1424
|
+
index name doesn't need to be derived from the column names.
|
|
1245
1425
|
|
|
1246
|
-
*
|
|
1247
|
-
`last`, `average`, `count`, `maximum`, `minimum`, and `sum`. Those
|
|
1248
|
-
new methods run `EXPLAIN` on the corresponding queries:
|
|
1426
|
+
*Ali Ismayiliov*
|
|
1249
1427
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
# EXPLAIN SELECT COUNT(*) FROM `users`
|
|
1253
|
-
# ...
|
|
1428
|
+
* Change the payload name of `sql.active_record` notification for eager
|
|
1429
|
+
loading from "SQL" to "#{model.name} Eager Load".
|
|
1254
1430
|
|
|
1255
|
-
|
|
1256
|
-
# EXPLAIN SELECT MAX(`users`.`id`) FROM `users`
|
|
1257
|
-
# ...
|
|
1258
|
-
```
|
|
1431
|
+
*zzak*
|
|
1259
1432
|
|
|
1260
|
-
|
|
1433
|
+
* Enable automatically retrying idempotent `#exists?` queries on connection
|
|
1434
|
+
errors.
|
|
1261
1435
|
|
|
1262
|
-
*
|
|
1263
|
-
when validating associated records.
|
|
1436
|
+
*Hartley McGuire*, *classidied*
|
|
1264
1437
|
|
|
1265
|
-
|
|
1438
|
+
* Deprecate usage of unsupported methods in conjunction with `update_all`:
|
|
1266
1439
|
|
|
1267
|
-
|
|
1440
|
+
`update_all` will now print a deprecation message if a query includes either `WITH`,
|
|
1441
|
+
`WITH RECURSIVE` or `DISTINCT` statements. Those were never supported and were ignored
|
|
1442
|
+
when generating the SQL query.
|
|
1268
1443
|
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
set as well.
|
|
1444
|
+
An error will be raised in a future Rails release. This behavior will be consistent
|
|
1445
|
+
with `delete_all` which currently raises an error for unsupported statements.
|
|
1272
1446
|
|
|
1273
|
-
|
|
1274
|
-
database: storage/development.sqlite3
|
|
1275
|
-
timeout: 5000
|
|
1276
|
-
pragmas:
|
|
1277
|
-
journal_mode: off
|
|
1278
|
-
temp_store: memory
|
|
1279
|
-
```
|
|
1447
|
+
*Edouard Chin*
|
|
1280
1448
|
|
|
1281
|
-
|
|
1449
|
+
* The table columns inside `schema.rb` are now sorted alphabetically.
|
|
1282
1450
|
|
|
1283
|
-
|
|
1451
|
+
Previously they'd be sorted by creation order, which can cause merge conflicts when two
|
|
1452
|
+
branches modify the same table concurrently.
|
|
1284
1453
|
|
|
1285
|
-
|
|
1286
|
-
with care, so instead of a warning most users won't see anyway, it's preferable to
|
|
1287
|
-
leave the configuration commented out to force them to think about having the database
|
|
1288
|
-
on a persistent volume etc.
|
|
1454
|
+
*John Duff*
|
|
1289
1455
|
|
|
1290
|
-
|
|
1456
|
+
* Introduce versions formatter for the schema dumper.
|
|
1291
1457
|
|
|
1292
|
-
|
|
1458
|
+
It is now possible to override how schema dumper formats versions information inside the
|
|
1459
|
+
`structure.sql` file. Currently, the versions are simply sorted in the decreasing order.
|
|
1460
|
+
Within large teams, this can potentially cause many merge conflicts near the top of the list.
|
|
1293
1461
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1462
|
+
Now, the custom formatter can be provided with a custom sorting logic (e.g. by hash values
|
|
1463
|
+
of the versions), which can greatly reduce the number of conflicts.
|
|
1296
1464
|
|
|
1297
|
-
|
|
1298
|
-
create_table :users do |t|
|
|
1299
|
-
t.string :name
|
|
1300
|
-
t.virtual :name_upper, type: :string, as: 'UPPER(name)'
|
|
1301
|
-
t.virtual :name_lower, type: :string, as: 'LOWER(name)', stored: true
|
|
1302
|
-
end
|
|
1303
|
-
```
|
|
1465
|
+
*fatkodima*
|
|
1304
1466
|
|
|
1305
|
-
|
|
1467
|
+
* Serialized attributes can now be marked as comparable.
|
|
1306
1468
|
|
|
1307
|
-
|
|
1469
|
+
A not rare issue when working with serialized attributes is that the serialized representation of an object
|
|
1470
|
+
can change over time. Either because you are migrating from one serializer to the other (e.g. YAML to JSON or to msgpack),
|
|
1471
|
+
or because the serializer used subtly changed its output.
|
|
1308
1472
|
|
|
1309
|
-
|
|
1473
|
+
One example is libyaml that used to have some extra trailing whitespaces, and recently fixed that.
|
|
1474
|
+
When this sorts of thing happen, you end up with lots of records that report being changed even though
|
|
1475
|
+
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.
|
|
1310
1476
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1477
|
+
The solution is to instead compare the deserialized representation of the object, however Active Record
|
|
1478
|
+
can't assume the deserialized object has a working `==` method. Hence why this new functionality is opt-in.
|
|
1479
|
+
|
|
1480
|
+
```ruby
|
|
1481
|
+
serialize :config, type: Hash, coder: JSON, comparable: true
|
|
1313
1482
|
```
|
|
1314
1483
|
|
|
1315
1484
|
*Jean Boussier*
|
|
1316
1485
|
|
|
1317
|
-
*
|
|
1318
|
-
`assert_no_queries_match` assertions public.
|
|
1486
|
+
* Fix MySQL default functions getting dropped when changing a column's nullability.
|
|
1319
1487
|
|
|
1320
|
-
|
|
1321
|
-
`assert_no_queries`. To assert that specific SQL queries are made, `assert_queries_match` and
|
|
1322
|
-
`assert_no_queries_match` are used. These assertions can now be used in applications as well.
|
|
1488
|
+
*Bastian Bartmann*
|
|
1323
1489
|
|
|
1324
|
-
|
|
1325
|
-
class ArticleTest < ActiveSupport::TestCase
|
|
1326
|
-
test "queries are made" do
|
|
1327
|
-
assert_queries_count(1) { Article.first }
|
|
1328
|
-
end
|
|
1490
|
+
* SQLite extensions can be configured in `config/database.yml`.
|
|
1329
1491
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1492
|
+
The database configuration option `extensions:` allows an application to load SQLite extensions
|
|
1493
|
+
when using `sqlite3` >= v2.4.0. The array members may be filesystem paths or the names of
|
|
1494
|
+
modules that respond to `.to_path`:
|
|
1495
|
+
|
|
1496
|
+
``` yaml
|
|
1497
|
+
development:
|
|
1498
|
+
adapter: sqlite3
|
|
1499
|
+
extensions:
|
|
1500
|
+
- SQLean::UUID # module name responding to `.to_path`
|
|
1501
|
+
- .sqlpkg/nalgeon/crypto/crypto.so # or a filesystem path
|
|
1502
|
+
- <%= AppExtensions.location %> # or ruby code returning a path
|
|
1336
1503
|
```
|
|
1337
1504
|
|
|
1338
|
-
*
|
|
1505
|
+
*Mike Dalessio*
|
|
1339
1506
|
|
|
1340
|
-
*
|
|
1507
|
+
* `ActiveRecord::Middleware::ShardSelector` supports granular database connection switching.
|
|
1341
1508
|
|
|
1342
|
-
|
|
1509
|
+
A new configuration option, `class_name:`, is introduced to
|
|
1510
|
+
`config.active_record.shard_selector` to allow an application to specify the abstract connection
|
|
1511
|
+
class to be switched by the shard selection middleware. The default class is
|
|
1512
|
+
`ActiveRecord::Base`.
|
|
1343
1513
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
set in the deployment environment.
|
|
1514
|
+
For example, this configuration tells `ShardSelector` to switch shards using
|
|
1515
|
+
`AnimalsRecord.connected_to`:
|
|
1347
1516
|
|
|
1348
|
-
```
|
|
1349
|
-
|
|
1350
|
-
config.active_record.protocol_adapters.mysql = "trilogy"
|
|
1351
|
-
# will connect to MySQL using the trilogy adapter
|
|
1517
|
+
```
|
|
1518
|
+
config.active_record.shard_selector = { class_name: "AnimalsRecord" }
|
|
1352
1519
|
```
|
|
1353
1520
|
|
|
1354
|
-
*
|
|
1521
|
+
*Mike Dalessio*
|
|
1355
1522
|
|
|
1356
|
-
*
|
|
1357
|
-
the `SHOW WARNINGS` query is executed, `ActiveRecord.db_warnings_action` proc will still be
|
|
1358
|
-
called with a generic warning message rather than silently ignoring the warning(s).
|
|
1523
|
+
* Reset relations after `insert_all`/`upsert_all`.
|
|
1359
1524
|
|
|
1360
|
-
|
|
1525
|
+
Bulk insert/upsert methods will now call `reset` if used on a relation, matching the behavior of `update_all`.
|
|
1361
1526
|
|
|
1362
|
-
*
|
|
1527
|
+
*Milo Winningham*
|
|
1363
1528
|
|
|
1364
|
-
|
|
1529
|
+
* Use `_N` as a parallel tests databases suffixes
|
|
1365
1530
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
column).
|
|
1531
|
+
Peviously, `-N` was used as a suffix. This can cause problems for RDBMSes
|
|
1532
|
+
which do not support dashes in database names.
|
|
1369
1533
|
|
|
1370
|
-
*
|
|
1534
|
+
*fatkodima*
|
|
1371
1535
|
|
|
1372
|
-
*
|
|
1536
|
+
* Remember when a database connection has recently been verified (for
|
|
1537
|
+
two seconds, by default), to avoid repeated reverifications during a
|
|
1538
|
+
single request.
|
|
1373
1539
|
|
|
1374
|
-
|
|
1540
|
+
This should recreate a similar rate of verification as in Rails 7.1,
|
|
1541
|
+
where connections are leased for the duration of a request, and thus
|
|
1542
|
+
only verified once.
|
|
1375
1543
|
|
|
1376
|
-
|
|
1377
|
-
Post.first.inspect #=> "#<Post id: 1>"
|
|
1378
|
-
```
|
|
1544
|
+
*Matthew Draper*
|
|
1379
1545
|
|
|
1380
|
-
|
|
1381
|
-
`ActiveRecord::Core#attributes_for_inspect`.
|
|
1546
|
+
* Allow to reset cache counters for multiple records.
|
|
1382
1547
|
|
|
1383
|
-
```ruby
|
|
1384
|
-
Post.attributes_for_inspect = [:id, :title]
|
|
1385
|
-
Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"
|
|
1386
1548
|
```
|
|
1387
|
-
|
|
1388
|
-
With `attributes_for_inspect` set to `:all`, `inspect` will list all the record's attributes.
|
|
1389
|
-
|
|
1390
|
-
```ruby
|
|
1391
|
-
Post.attributes_for_inspect = :all
|
|
1392
|
-
Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
|
|
1549
|
+
Aircraft.reset_counters([1, 2, 3], :wheels_count)
|
|
1393
1550
|
```
|
|
1394
1551
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
You can also call `full_inspect` to get an inspection with all the attributes.
|
|
1398
|
-
|
|
1399
|
-
The attributes in `attribute_for_inspect` will also be used for `pretty_print`.
|
|
1400
|
-
|
|
1401
|
-
*Andrew Novoselac*
|
|
1402
|
-
|
|
1403
|
-
* Don't mark attributes as changed when reassigned to `Float::INFINITY` or
|
|
1404
|
-
`-Float::INFINITY`.
|
|
1552
|
+
It produces much fewer queries compared to the custom implementation using looping over ids.
|
|
1553
|
+
Previously: `O(ids.size * counters.size)` queries, now: `O(ids.size + counters.size)` queries.
|
|
1405
1554
|
|
|
1406
|
-
*
|
|
1555
|
+
*fatkodima*
|
|
1407
1556
|
|
|
1408
|
-
*
|
|
1557
|
+
* Add `affected_rows` to `sql.active_record` Notification.
|
|
1409
1558
|
|
|
1410
|
-
*
|
|
1559
|
+
*Hartley McGuire*
|
|
1411
1560
|
|
|
1412
|
-
*
|
|
1561
|
+
* Fix `sum` when performing a grouped calculation.
|
|
1413
1562
|
|
|
1414
|
-
|
|
1563
|
+
`User.group(:friendly).sum` no longer worked. This is fixed.
|
|
1415
1564
|
|
|
1416
|
-
|
|
1417
|
-
add_reference :person, :alias, foreign_key: { deferrable: :deferred }
|
|
1418
|
-
add_reference :alias, :person, foreign_key: { deferrable: :deferred }
|
|
1419
|
-
```
|
|
1565
|
+
*Edouard Chin*
|
|
1420
1566
|
|
|
1421
|
-
|
|
1567
|
+
* Add support for enabling or disabling transactional tests per database.
|
|
1422
1568
|
|
|
1423
|
-
|
|
1569
|
+
A test class can now override the default `use_transactional_tests` setting
|
|
1570
|
+
for individual databases, which can be useful if some databases need their
|
|
1571
|
+
current state to be accessible to an external process while tests are running.
|
|
1424
1572
|
|
|
1425
1573
|
```ruby
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
Post.connection.set_constraints(:deferred)
|
|
1430
|
-
p = Post.create!(user_id: -1)
|
|
1431
|
-
u = User.create!
|
|
1432
|
-
p.user = u
|
|
1433
|
-
p.save!
|
|
1574
|
+
class MostlyTransactionalTest < ActiveSupport::TestCase
|
|
1575
|
+
self.use_transactional_tests = true
|
|
1576
|
+
skip_transactional_tests_for_database :shared
|
|
1434
1577
|
end
|
|
1435
1578
|
```
|
|
1436
1579
|
|
|
1437
|
-
*
|
|
1438
|
-
|
|
1439
|
-
* Include `ActiveModel::API` in `ActiveRecord::Base`.
|
|
1440
|
-
|
|
1441
|
-
*Sean Doyle*
|
|
1580
|
+
*Matthew Cheetham*, *Morgan Mareve*
|
|
1442
1581
|
|
|
1443
|
-
*
|
|
1582
|
+
* Cast `query_cache` value when using URL configuration.
|
|
1444
1583
|
|
|
1445
|
-
*
|
|
1446
|
-
|
|
1447
|
-
* Add `nulls_last` and working `desc.nulls_first` for MySQL.
|
|
1584
|
+
*zzak*
|
|
1448
1585
|
|
|
1449
|
-
|
|
1586
|
+
* NULLS NOT DISTINCT works with UNIQUE CONSTRAINT as well as UNIQUE INDEX.
|
|
1450
1587
|
|
|
1451
|
-
*
|
|
1588
|
+
*Ryuta Kamizono*
|
|
1452
1589
|
|
|
1453
|
-
|
|
1454
|
-
Topic.includes(:posts).order(posts: { created_at: :desc })
|
|
1455
|
-
```
|
|
1590
|
+
* `PG::UnableToSend: no connection to the server` is now retryable as a connection-related exception
|
|
1456
1591
|
|
|
1457
|
-
*
|
|
1592
|
+
*Kazuma Watanabe*
|
|
1458
1593
|
|
|
1459
|
-
Please check [
|
|
1594
|
+
Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/activerecord/CHANGELOG.md) for previous changes.
|