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