activerecord 6.1.7 → 7.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 +1516 -1019
- data/MIT-LICENSE +1 -1
- data/README.rdoc +17 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +50 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +35 -31
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -16
- data/lib/active_record/associations/preloader/association.rb +207 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +423 -289
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +61 -14
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +25 -10
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +10 -13
- data/lib/active_record/attribute_methods.rb +121 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +61 -30
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +18 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +381 -69
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +65 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +107 -136
- data/lib/active_record/core.rb +194 -224
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +84 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +61 -15
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +224 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +172 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +92 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +96 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +156 -62
- data/lib/active_record/errors.rb +171 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +131 -86
- data/lib/active_record/future_result.rb +164 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +133 -20
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +117 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +36 -21
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +108 -13
- data/lib/active_record/migration/compatibility.rb +221 -48
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +355 -171
- data/lib/active_record/model_schema.rb +116 -97
- data/lib/active_record/nested_attributes.rb +36 -15
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +405 -85
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +219 -43
- data/lib/active_record/railties/controller_runtime.rb +13 -9
- data/lib/active_record/railties/databases.rake +185 -249
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +229 -80
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +211 -90
- data/lib/active_record/relation/delegation.rb +27 -13
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +654 -127
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +262 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +18 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +225 -136
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +116 -96
- data/lib/active_record/timestamp.rb +28 -17
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +139 -19
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +92 -13
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
data/CHANGELOG.md
CHANGED
@@ -1,1767 +1,2264 @@
|
|
1
|
-
## Rails
|
1
|
+
## Rails 7.1.0 (October 05, 2023) ##
|
2
2
|
|
3
|
-
*
|
3
|
+
* No changes.
|
4
4
|
|
5
|
-
*Étienne Barrié*
|
6
5
|
|
7
|
-
|
6
|
+
## Rails 7.1.0.rc2 (October 01, 2023) ##
|
8
7
|
|
9
|
-
|
10
|
-
which is wasteful and cause problem with YAML safe_load.
|
8
|
+
* Remove -shm and -wal SQLite files when `rails db:drop` is run.
|
11
9
|
|
12
|
-
*
|
10
|
+
*Niklas Häusele*
|
13
11
|
|
14
|
-
*
|
12
|
+
* Revert the change to raise an `ArgumentError` when `#accepts_nested_attributes_for` is declared more than once for
|
13
|
+
an association in the same class.
|
15
14
|
|
16
|
-
|
15
|
+
The reverted behavior broke the case where the `#accepts_nested_attributes_for` was defined in a concern and
|
16
|
+
where overridden in the class that included the concern.
|
17
17
|
|
18
|
-
*
|
18
|
+
*Rafael Mendonça França*
|
19
|
+
|
20
|
+
|
21
|
+
## Rails 7.1.0.rc1 (September 27, 2023) ##
|
19
22
|
|
20
|
-
|
23
|
+
* Better naming for unique constraints support.
|
21
24
|
|
22
|
-
|
25
|
+
Naming unique keys leads to misunderstanding it's a short-hand of unique indexes.
|
26
|
+
Just naming it unique constraints is not misleading.
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
When set to true, this configuration option tells Rails to use the old
|
30
|
-
"unsafe" YAML loading strategy, maintaining the existing behavior but leaving
|
31
|
-
the possible escalation vulnerability in place. Setting this option to true
|
32
|
-
is *not* recommended, but can aid in upgrading.
|
33
|
-
|
34
|
-
* `config.active_record.yaml_column_permitted_classes`
|
35
|
-
|
36
|
-
The "safe YAML" loading method does not allow all classes to be deserialized
|
37
|
-
by default. This option allows you to specify classes deemed "safe" in your
|
38
|
-
application. For example, if your application uses Symbol and Time in
|
39
|
-
serialized data, you can add Symbol and Time to the allowed list as follows:
|
40
|
-
|
28
|
+
In Rails 7.1.0.beta1 or before:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
|
32
|
+
remove_unique_key :sections, name: "unique_section_position"
|
41
33
|
```
|
42
|
-
|
34
|
+
|
35
|
+
Now:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
add_unique_constraint :sections, [:position], deferrable: :deferred, name: "unique_section_position"
|
39
|
+
remove_unique_constraint :sections, name: "unique_section_position"
|
43
40
|
```
|
44
41
|
|
45
|
-
|
42
|
+
*Ryuta Kamizono*
|
46
43
|
|
44
|
+
* Fix duplicate quoting for check constraint expressions in schema dump when using MySQL
|
47
45
|
|
48
|
-
|
46
|
+
A check constraint with an expression, that already contains quotes, lead to an invalid schema
|
47
|
+
dump with the mysql2 adapter.
|
49
48
|
|
50
|
-
|
49
|
+
Fixes #42424.
|
51
50
|
|
51
|
+
*Felix Tscheulin*
|
52
52
|
|
53
|
-
|
53
|
+
* Performance tune the SQLite3 adapter connection configuration
|
54
54
|
|
55
|
-
|
55
|
+
For Rails applications, the Write-Ahead-Log in normal syncing mode with a capped journal size, a healthy shared memory buffer and a shared cache will perform, on average, 2× better.
|
56
56
|
|
57
|
+
*Stephen Margheim*
|
57
58
|
|
58
|
-
|
59
|
+
* Allow SQLite3 `busy_handler` to be configured with simple max number of `retries`
|
59
60
|
|
60
|
-
|
61
|
+
Retrying busy connections without delay is a preferred practice for performance-sensitive applications. Add support for a `database.yml` `retries` integer, which is used in a simple `busy_handler` function to retry busy connections without exponential backoff up to the max number of `retries`.
|
61
62
|
|
62
|
-
|
63
|
-
In Ruby 2.6, the receiver of the `String#-@` method is modified under certain circumstances.
|
64
|
-
This was later identified as a bug (https://bugs.ruby-lang.org/issues/15926) and only
|
65
|
-
fixed in Ruby 2.7.
|
63
|
+
*Stephen Margheim*
|
66
64
|
|
67
|
-
|
68
|
-
`ActiveRecord::ConnectionAdapters::SchemaCache#deep_deduplicate` method, which internally
|
69
|
-
calls the `String#-@` method, could also modify an input string argument in Ruby 2.6 --
|
70
|
-
changing a tainted, unfrozen string into a tainted, frozen string.
|
65
|
+
* The SQLite3 adapter now supports `supports_insert_returning?`
|
71
66
|
|
72
|
-
|
67
|
+
Implementing the full `supports_insert_returning?` contract means the SQLite3 adapter supports auto-populated columns (#48241) as well as custom primary keys.
|
73
68
|
|
74
|
-
*
|
69
|
+
*Stephen Margheim*
|
75
70
|
|
76
|
-
*
|
77
|
-
migration version is 6.0.
|
71
|
+
* Ensure the SQLite3 adapter handles default functions with the `||` concatenation operator
|
78
72
|
|
79
|
-
|
80
|
-
|
73
|
+
Previously, this default function would produce the static string `"'Ruby ' || 'on ' || 'Rails'"`.
|
74
|
+
Now, the adapter will appropriately receive and use `"Ruby on Rails"`.
|
81
75
|
|
82
|
-
|
76
|
+
```ruby
|
77
|
+
change_column_default "test_models", "ruby_on_rails", -> { "('Ruby ' || 'on ' || 'Rails')" }
|
78
|
+
```
|
83
79
|
|
84
|
-
*
|
80
|
+
*Stephen Margheim*
|
85
81
|
|
86
|
-
|
82
|
+
* Dump PostgreSQL schemas as part of the schema dump.
|
83
|
+
|
84
|
+
*Lachlan Sylvester*
|
85
|
+
|
86
|
+
|
87
|
+
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
87
88
|
|
88
|
-
*
|
89
|
+
* Encryption now supports `support_unencrypted_data` being set per-attribute.
|
90
|
+
|
91
|
+
You can now opt out of `support_unencrypted_data` on a specific encrypted attribute.
|
92
|
+
This only has an effect if `ActiveRecord::Encryption.config.support_unencrypted_data == true`.
|
89
93
|
|
90
94
|
```ruby
|
91
|
-
|
95
|
+
class User < ActiveRecord::Base
|
96
|
+
encrypts :name, deterministic: true, support_unencrypted_data: false
|
97
|
+
encrypts :email, deterministic: true
|
98
|
+
end
|
92
99
|
```
|
93
100
|
|
94
|
-
|
95
|
-
responsible to detect write queries.
|
101
|
+
*Alex Ghiculescu*
|
96
102
|
|
97
|
-
|
98
|
-
not be able to handle it, but will either succeed or failed in a more correct way.
|
103
|
+
* Add instrumentation for Active Record transactions
|
99
104
|
|
100
|
-
|
105
|
+
Allows subscribing to transaction events for tracking/instrumentation. The event payload contains the connection and the outcome (commit, rollback, restart, incomplete), as well as timing details.
|
101
106
|
|
102
|
-
|
107
|
+
```ruby
|
108
|
+
ActiveSupport::Notifications.subscribe("transaction.active_record") do |event|
|
109
|
+
puts "Transaction event occurred!"
|
110
|
+
connection = event.payload[:connection]
|
111
|
+
puts "Connection: #{connection.inspect}"
|
112
|
+
end
|
113
|
+
```
|
103
114
|
|
104
|
-
*
|
115
|
+
*Daniel Colson*, *Ian Candy*
|
105
116
|
|
106
|
-
*
|
107
|
-
`has_many` through relations.
|
117
|
+
* Support composite foreign keys via migration helpers.
|
108
118
|
|
109
|
-
|
119
|
+
```ruby
|
120
|
+
# Assuming "carts" table has "(shop_id, user_id)" as a primary key.
|
110
121
|
|
111
|
-
|
122
|
+
add_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id])
|
112
123
|
|
113
|
-
|
114
|
-
|
124
|
+
remove_foreign_key(:orders, :carts, primary_key: [:shop_id, :user_id])
|
125
|
+
foreign_key_exists?(:orders, :carts, primary_key: [:shop_id, :user_id])
|
126
|
+
```
|
115
127
|
|
116
|
-
|
117
|
-
various DB management tasks.
|
128
|
+
*fatkodima*
|
118
129
|
|
119
|
-
|
130
|
+
* Adds support for `if_not_exists` when adding a check constraint.
|
120
131
|
|
121
|
-
|
132
|
+
```ruby
|
133
|
+
add_check_constraint :posts, "post_type IN ('blog', 'comment', 'share')", if_not_exists: true
|
134
|
+
```
|
122
135
|
|
123
|
-
*
|
136
|
+
*Cody Cutrer*
|
124
137
|
|
125
|
-
|
138
|
+
* Raise an `ArgumentError` when `#accepts_nested_attributes_for` is declared more than once for an association in
|
139
|
+
the same class. Previously, the last declaration would silently override the previous one. Overriding in a subclass
|
140
|
+
is still allowed.
|
126
141
|
|
127
|
-
*
|
142
|
+
*Joshua Young*
|
128
143
|
|
129
|
-
|
144
|
+
* Deprecate `rewhere` argument on `#merge`.
|
130
145
|
|
131
|
-
|
146
|
+
The `rewhere` argument on `#merge`is deprecated without replacement and
|
147
|
+
will be removed in Rails 7.2.
|
132
148
|
|
133
|
-
*
|
149
|
+
*Adam Hess*
|
134
150
|
|
135
|
-
|
151
|
+
* Fix unscope is not working in specific case
|
136
152
|
|
137
|
-
|
153
|
+
Before:
|
154
|
+
```ruby
|
155
|
+
Post.where(id: 1...3).unscope(where: :id).to_sql # "SELECT `posts`.* FROM `posts` WHERE `posts`.`id` >= 1 AND `posts`.`id` < 3"
|
138
156
|
|
139
|
-
|
157
|
+
```
|
140
158
|
|
159
|
+
After:
|
160
|
+
```ruby
|
161
|
+
Post.where(id: 1...3).unscope(where: :id).to_sql # "SELECT `posts`.* FROM `posts`"
|
162
|
+
```
|
141
163
|
|
142
|
-
|
164
|
+
Fixes #48094.
|
143
165
|
|
144
|
-
*
|
166
|
+
*Kazuya Hatanaka*
|
145
167
|
|
168
|
+
* Change `has_secure_token` default to `on: :initialize`
|
146
169
|
|
147
|
-
|
170
|
+
Change the new default value from `on: :create` to `on: :initialize`
|
148
171
|
|
149
|
-
|
172
|
+
Can be controlled by the `config.active_record.generate_secure_token_on`
|
173
|
+
configuration:
|
150
174
|
|
175
|
+
```ruby
|
176
|
+
config.active_record.generate_secure_token_on = :create
|
177
|
+
```
|
151
178
|
|
152
|
-
|
179
|
+
*Sean Doyle*
|
153
180
|
|
154
|
-
*
|
181
|
+
* Fix `change_column` not setting `precision: 6` on `datetime` columns when
|
182
|
+
using 7.0+ Migrations and SQLite.
|
155
183
|
|
184
|
+
*Hartley McGuire*
|
156
185
|
|
157
|
-
|
186
|
+
* Support composite identifiers in `to_key`
|
158
187
|
|
159
|
-
|
188
|
+
`to_key` avoids wrapping `#id` value into an `Array` if `#id` already an array
|
160
189
|
|
190
|
+
*Nikita Vasilevsky*
|
161
191
|
|
162
|
-
|
192
|
+
* Add validation option for `enum`
|
163
193
|
|
164
|
-
|
194
|
+
```ruby
|
195
|
+
class Contract < ApplicationRecord
|
196
|
+
enum :status, %w[in_progress completed], validate: true
|
197
|
+
end
|
198
|
+
Contract.new(status: "unknown").valid? # => false
|
199
|
+
Contract.new(status: nil).valid? # => false
|
200
|
+
Contract.new(status: "completed").valid? # => true
|
165
201
|
|
202
|
+
class Contract < ApplicationRecord
|
203
|
+
enum :status, %w[in_progress completed], validate: { allow_nil: true }
|
204
|
+
end
|
205
|
+
Contract.new(status: "unknown").valid? # => false
|
206
|
+
Contract.new(status: nil).valid? # => true
|
207
|
+
Contract.new(status: "completed").valid? # => true
|
208
|
+
```
|
166
209
|
|
167
|
-
|
210
|
+
*Edem Topuzov*, *Ryuta Kamizono*
|
168
211
|
|
169
|
-
*
|
212
|
+
* Allow batching methods to use already loaded relation if available
|
170
213
|
|
214
|
+
Calling batch methods on already loaded relations will use the records previously loaded instead of retrieving
|
215
|
+
them from the database again.
|
171
216
|
|
172
|
-
|
217
|
+
*Adam Hess*
|
173
218
|
|
174
|
-
*
|
219
|
+
* Deprecate `read_attribute(:id)` returning the primary key if the primary key is not `:id`.
|
175
220
|
|
221
|
+
Starting in Rails 7.2, `read_attribute(:id)` will return the value of the id column, regardless of the model's
|
222
|
+
primary key. To retrieve the value of the primary key, use `#id` instead. `read_attribute(:id)` for composite
|
223
|
+
primary key models will now return the value of the id column.
|
176
224
|
|
177
|
-
|
225
|
+
*Adrianna Chang*
|
178
226
|
|
179
|
-
*
|
227
|
+
* Fix `change_table` setting datetime precision for 6.1 Migrations
|
180
228
|
|
181
|
-
*
|
229
|
+
*Hartley McGuire*
|
182
230
|
|
183
|
-
*
|
231
|
+
* Fix change_column setting datetime precision for 6.1 Migrations
|
184
232
|
|
185
|
-
*
|
233
|
+
*Hartley McGuire*
|
186
234
|
|
187
|
-
*
|
235
|
+
* Add `ActiveRecord::Base#id_value` alias to access the raw value of a record's id column.
|
188
236
|
|
189
|
-
|
190
|
-
Active Record's schema cache loader and `YAMLColumn` now uses `YAML.unsafe_load` if available.
|
237
|
+
This alias is only provided for models that declare an `:id` column.
|
191
238
|
|
192
|
-
*
|
239
|
+
*Adrianna Chang*
|
193
240
|
|
194
|
-
*
|
241
|
+
* Fix previous change tracking for `ActiveRecord::Store` when using a column with JSON structured database type
|
195
242
|
|
196
|
-
|
243
|
+
Before, the methods to access the changes made during the last save `#saved_change_to_key?`, `#saved_change_to_key`, and `#key_before_last_save` did not work if the store was defined as a `store_accessor` on a column with a JSON structured database type
|
197
244
|
|
198
|
-
*
|
245
|
+
*Robert DiMartino*
|
199
246
|
|
200
|
-
|
247
|
+
* Fully support `NULLS [NOT] DISTINCT` for PostgreSQL 15+ indexes.
|
201
248
|
|
202
|
-
|
249
|
+
Previous work was done to allow the index to be created in a migration, but it was not
|
250
|
+
supported in schema.rb. Additionally, the matching for `NULLS [NOT] DISTINCT` was not
|
251
|
+
in the correct order, which could have resulted in inconsistent schema detection.
|
203
252
|
|
204
|
-
*
|
253
|
+
*Gregory Jones*
|
205
254
|
|
206
|
-
*
|
255
|
+
* Allow escaping of literal colon characters in `sanitize_sql_*` methods when named bind variables are used
|
207
256
|
|
208
|
-
*
|
257
|
+
*Justin Bull*
|
209
258
|
|
210
|
-
*
|
259
|
+
* Fix `#previously_new_record?` to return true for destroyed records.
|
211
260
|
|
212
|
-
|
261
|
+
Before, if a record was created and then destroyed, `#previously_new_record?` would return true.
|
262
|
+
Now, any UPDATE or DELETE to a record is considered a change, and will result in `#previously_new_record?`
|
263
|
+
returning false.
|
213
264
|
|
214
|
-
*
|
215
|
-
`quoted_node` so that PostgreSQL arrays are quoted properly.
|
265
|
+
*Adrianna Chang*
|
216
266
|
|
217
|
-
|
267
|
+
* Specify callback in `has_secure_token`
|
218
268
|
|
219
|
-
|
269
|
+
```ruby
|
270
|
+
class User < ApplicationRecord
|
271
|
+
has_secure_token on: :initialize
|
272
|
+
end
|
220
273
|
|
221
|
-
|
274
|
+
User.new.token # => "abc123...."
|
275
|
+
```
|
222
276
|
|
223
|
-
*
|
277
|
+
*Sean Doyle*
|
224
278
|
|
225
|
-
|
279
|
+
* Fix incrementation of in memory counter caches when associations overlap
|
226
280
|
|
227
|
-
|
281
|
+
When two associations had a similarly named counter cache column, Active Record
|
282
|
+
could sometime increment the wrong one.
|
228
283
|
|
229
|
-
*
|
284
|
+
*Jacopo Beschi*, *Jean Boussier*
|
230
285
|
|
231
|
-
*
|
286
|
+
* Don't show secrets for Active Record's `Cipher::Aes256Gcm#inspect`.
|
232
287
|
|
233
|
-
|
234
|
-
relation set `strict_loading` to false the false wasn't considered when
|
235
|
-
deciding whether to raise/warn about strict loading.
|
288
|
+
Before:
|
236
289
|
|
290
|
+
```ruby
|
291
|
+
ActiveRecord::Encryption::Cipher::Aes256Gcm.new(secret).inspect
|
292
|
+
"#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038 ... @secret=\"\\xAF\\bFh]LV}q\\nl\\xB2U\\xB3 ... >"
|
293
|
+
```
|
294
|
+
|
295
|
+
After:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
ActiveRecord::Encryption::Cipher::Aes256Gcm(secret).inspect
|
299
|
+
"#<ActiveRecord::Encryption::Cipher::Aes256Gcm:0x0000000104888038>"
|
237
300
|
```
|
238
|
-
class Dog < ActiveRecord::Base
|
239
|
-
self.strict_loading_by_default = true
|
240
301
|
|
241
|
-
|
302
|
+
*Petrik de Heus*
|
303
|
+
|
304
|
+
* Bring back the historical behavior of committing transaction on non-local return.
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
Model.transaction do
|
308
|
+
model.save
|
309
|
+
return
|
310
|
+
other_model.save # not executed
|
242
311
|
end
|
243
312
|
```
|
244
313
|
|
245
|
-
|
246
|
-
`
|
247
|
-
Active Storage which is why I made this PR superseding #41461. We need
|
248
|
-
to fix this for all applications since the behavior is a little
|
249
|
-
surprising. I took the test from #41461 and the code suggestion from #41453
|
250
|
-
with some additions.
|
314
|
+
Historically only raised errors would trigger a rollback, but in Ruby `2.3`, the `timeout` library
|
315
|
+
started using `throw` to interrupt execution which had the adverse effect of committing open transactions.
|
251
316
|
|
252
|
-
|
317
|
+
To solve this, in Active Record 6.1 the behavior was changed to instead rollback the transaction as it was safer
|
318
|
+
than to potentially commit an incomplete transaction.
|
253
319
|
|
254
|
-
|
320
|
+
Using `return`, `break` or `throw` inside a `transaction` block was essentially deprecated from Rails 6.1 onwards.
|
255
321
|
|
256
|
-
|
322
|
+
However with the release of `timeout 0.4.0`, `Timeout.timeout` now raises an error again, and Active Record is able
|
323
|
+
to return to its original, less surprising, behavior.
|
257
324
|
|
258
|
-
|
325
|
+
This historical behavior can now be opt-ed in via:
|
259
326
|
|
260
|
-
|
327
|
+
```
|
328
|
+
Rails.application.config.active_record.commit_transaction_on_non_local_return = true
|
329
|
+
```
|
261
330
|
|
262
|
-
|
331
|
+
And is the default for new applications created in Rails 7.1.
|
263
332
|
|
264
|
-
*
|
333
|
+
*Jean Boussier*
|
265
334
|
|
266
|
-
*
|
335
|
+
* Deprecate `name` argument on `#remove_connection`.
|
267
336
|
|
268
|
-
|
337
|
+
The `name` argument is deprecated on `#remove_connection` without replacement. `#remove_connection` should be called directly on the class that established the connection.
|
269
338
|
|
270
|
-
*
|
339
|
+
*Eileen M. Uchitelle*
|
271
340
|
|
272
|
-
|
341
|
+
* Fix has_one through singular building with inverse.
|
273
342
|
|
343
|
+
Allows building of records from an association with a has_one through a
|
344
|
+
singular association with inverse. For belongs_to through associations,
|
345
|
+
linking the foreign key to the primary key model isn't needed.
|
346
|
+
For has_one, we cannot build records due to the association not being mutable.
|
274
347
|
|
275
|
-
|
348
|
+
*Gannon McGibbon*
|
276
349
|
|
277
|
-
*
|
350
|
+
* Disable database prepared statements when query logs are enabled
|
278
351
|
|
352
|
+
Prepared Statements and Query Logs are incompatible features due to query logs making every query unique.
|
279
353
|
|
280
|
-
|
354
|
+
*zzak, Jean Boussier*
|
281
355
|
|
282
|
-
*
|
356
|
+
* Support decrypting data encrypted non-deterministically with a SHA1 hash digest.
|
283
357
|
|
358
|
+
This adds a new Active Record encryption option to support decrypting data encrypted
|
359
|
+
non-deterministically with a SHA1 hash digest:
|
284
360
|
|
285
|
-
|
361
|
+
```
|
362
|
+
Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true
|
363
|
+
```
|
286
364
|
|
287
|
-
|
288
|
-
|
365
|
+
The new option addresses a problem when upgrading from 7.0 to 7.1. Due to a bug in how Active Record
|
366
|
+
Encryption was getting initialized, the key provider used for non-deterministic encryption were using
|
367
|
+
SHA-1 as its digest class, instead of the one configured globally by Rails via
|
368
|
+
`Rails.application.config.active_support.key_generator_hash_digest_class`.
|
289
369
|
|
290
|
-
*
|
370
|
+
*Cadu Ribeiro and Jorge Manrubia*
|
291
371
|
|
292
|
-
*
|
293
|
-
are enabled.
|
372
|
+
* Added PostgreSQL migration commands for enum rename, add value, and rename value.
|
294
373
|
|
295
|
-
|
374
|
+
`rename_enum` and `rename_enum_value` are reversible. Due to Postgres
|
375
|
+
limitation, `add_enum_value` is not reversible since you cannot delete enum
|
376
|
+
values. As an alternative you should drop and recreate the enum entirely.
|
377
|
+
|
378
|
+
```ruby
|
379
|
+
rename_enum :article_status, to: :article_state
|
380
|
+
```
|
296
381
|
|
297
|
-
|
298
|
-
|
382
|
+
```ruby
|
383
|
+
add_enum_value :article_state, "archived" # will be at the end of existing values
|
384
|
+
add_enum_value :article_state, "in review", before: "published"
|
385
|
+
add_enum_value :article_state, "approved", after: "in review"
|
386
|
+
```
|
299
387
|
|
300
|
-
|
388
|
+
```ruby
|
389
|
+
rename_enum_value :article_state, from: "archived", to: "deleted"
|
390
|
+
```
|
301
391
|
|
302
|
-
*
|
303
|
-
with a having clause
|
392
|
+
*Ray Faddis*
|
304
393
|
|
305
|
-
|
306
|
-
references an aliased select value would generate an error when
|
307
|
-
#include? was called, due to an optimisation that would generate
|
308
|
-
call #exists? on the relation instead, which effectively alters
|
309
|
-
the select values of the query (and thus removes the aliased select
|
310
|
-
values), but leaves the having clause intact. Because the having
|
311
|
-
clause is then referencing an aliased column that is no longer
|
312
|
-
present in the simplified query, an ActiveRecord::InvalidStatement
|
313
|
-
error was raised.
|
394
|
+
* Allow composite primary key to be derived from schema
|
314
395
|
|
315
|
-
|
396
|
+
Booting an application with a schema that contains composite primary keys
|
397
|
+
will not issue warning and won't `nil`ify the `ActiveRecord::Base#primary_key` value anymore.
|
316
398
|
|
399
|
+
Given a `travel_routes` table definition and a `TravelRoute` model like:
|
317
400
|
```ruby
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
401
|
+
create_table :travel_routes, primary_key: [:origin, :destination], force: true do |t|
|
402
|
+
t.string :origin
|
403
|
+
t.string :destination
|
404
|
+
end
|
405
|
+
|
406
|
+
class TravelRoute < ActiveRecord::Base; end
|
323
407
|
```
|
408
|
+
The `TravelRoute.primary_key` value will be automatically derived to `["origin", "destination"]`
|
324
409
|
|
325
|
-
|
326
|
-
simplified #exists? query, which simply checks for the presence of
|
327
|
-
a having clause.
|
410
|
+
*Nikita Vasilevsky*
|
328
411
|
|
329
|
-
|
412
|
+
* Include the `connection_pool` with exceptions raised from an adapter.
|
330
413
|
|
331
|
-
|
414
|
+
The `connection_pool` provides added context such as the connection used
|
415
|
+
that led to the exception as well as which role and shard.
|
332
416
|
|
333
|
-
*
|
334
|
-
without Rails knowledge (e.g., if app gets kill -9d during long-running query or due to Rack::Timeout), app won't end
|
335
|
-
up in perpetual crash state for being inconsistent with Postgres.
|
417
|
+
*Luan Vieira*
|
336
418
|
|
337
|
-
|
419
|
+
* Support multiple column ordering for `find_each`, `find_in_batches` and `in_batches`.
|
338
420
|
|
421
|
+
When find_each/find_in_batches/in_batches are performed on a table with composite primary keys, ascending or descending order can be selected for each key.
|
339
422
|
|
340
|
-
|
423
|
+
```ruby
|
424
|
+
Person.find_each(order: [:desc, :asc]) do |person|
|
425
|
+
person.party_all_night!
|
426
|
+
end
|
427
|
+
```
|
341
428
|
|
342
|
-
*
|
429
|
+
*Takuya Kurimoto*
|
343
430
|
|
344
|
-
|
345
|
-
for validating the money format in the PostgreSQL adapter. This patch
|
346
|
-
fixes the regexp.
|
431
|
+
* Fix where on association with has_one/has_many polymorphic relations.
|
347
432
|
|
348
|
-
|
433
|
+
Before:
|
434
|
+
```ruby
|
435
|
+
Treasure.where(price_estimates: PriceEstimate.all)
|
436
|
+
#=> SELECT (...) WHERE "treasures"."id" IN (SELECT "price_estimates"."estimate_of_id" FROM "price_estimates")
|
437
|
+
```
|
349
438
|
|
350
|
-
|
439
|
+
Later:
|
440
|
+
```ruby
|
441
|
+
Treasure.where(price_estimates: PriceEstimate.all)
|
442
|
+
#=> SELECT (...) WHERE "treasures"."id" IN (SELECT "price_estimates"."estimate_of_id" FROM "price_estimates" WHERE "price_estimates"."estimate_of_type" = 'Treasure')
|
443
|
+
```
|
351
444
|
|
352
|
-
*
|
445
|
+
*Lázaro Nixon*
|
446
|
+
|
447
|
+
* Assign auto populated columns on Active Record record creation.
|
448
|
+
|
449
|
+
Changes record creation logic to allow for the `auto_increment` column to be assigned
|
450
|
+
immediately after creation regardless of it's relation to the model's primary key.
|
353
451
|
|
452
|
+
The PostgreSQL adapter benefits the most from the change allowing for any number of auto-populated
|
453
|
+
columns to be assigned on the object immediately after row insertion utilizing the `RETURNING` statement.
|
354
454
|
|
355
|
-
|
455
|
+
*Nikita Vasilevsky*
|
456
|
+
|
457
|
+
* Use the first key in the `shards` hash from `connected_to` for the `default_shard`.
|
458
|
+
|
459
|
+
Some applications may not want to use `:default` as a shard name in their connection model. Unfortunately Active Record expects there to be a `:default` shard because it must assume a shard to get the right connection from the pool manager. Rather than force applications to manually set this, `connects_to` can infer the default shard name from the hash of shards and will now assume that the first shard is your default.
|
356
460
|
|
357
|
-
|
461
|
+
For example if your model looked like this:
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
class ShardRecord < ApplicationRecord
|
465
|
+
self.abstract_class = true
|
466
|
+
|
467
|
+
connects_to shards: {
|
468
|
+
shard_one: { writing: :shard_one },
|
469
|
+
shard_two: { writing: :shard_two }
|
470
|
+
}
|
471
|
+
```
|
472
|
+
|
473
|
+
Then the `default_shard` for this class would be set to `shard_one`.
|
474
|
+
|
475
|
+
Fixes: #45390
|
358
476
|
|
359
477
|
*Eileen M. Uchitelle*
|
360
478
|
|
361
|
-
*
|
479
|
+
* Fix mutation detection for serialized attributes backed by binary columns.
|
362
480
|
|
363
|
-
|
364
|
-
case the job would enqueue even though the database deletion
|
365
|
-
rolledback putting things in a funky state.
|
481
|
+
*Jean Boussier*
|
366
482
|
|
367
|
-
|
483
|
+
* Add `ActiveRecord.disconnect_all!` method to immediately close all connections from all pools.
|
368
484
|
|
369
|
-
*
|
485
|
+
*Jean Boussier*
|
370
486
|
|
371
|
-
*
|
487
|
+
* Discard connections which may have been left in a transaction.
|
372
488
|
|
373
|
-
|
489
|
+
There are cases where, due to an error, `within_new_transaction` may unexpectedly leave a connection in an open transaction. In these cases the connection may be reused, and the following may occur:
|
490
|
+
- Writes appear to fail when they actually succeed.
|
491
|
+
- Writes appear to succeed when they actually fail.
|
492
|
+
- Reads return stale or uncommitted data.
|
374
493
|
|
375
|
-
|
376
|
-
|
377
|
-
urls with the "jdbc" prefix were passed to the Active Record Adapter, others
|
378
|
-
are assumed to be adapter specification urls.
|
494
|
+
Previously, the following case was detected:
|
495
|
+
- An error is encountered during the transaction, then another error is encountered while attempting to roll it back.
|
379
496
|
|
380
|
-
|
497
|
+
Now, the following additional cases are detected:
|
498
|
+
- An error is encountered just after successfully beginning a transaction.
|
499
|
+
- An error is encountered while committing a transaction, then another error is encountered while attempting to roll it back.
|
500
|
+
- An error is encountered while rolling back a transaction.
|
381
501
|
|
382
|
-
*
|
502
|
+
*Nick Dower*
|
383
503
|
|
384
|
-
*
|
504
|
+
* Active Record query cache now evicts least recently used entries
|
385
505
|
|
386
|
-
|
506
|
+
By default it only keeps the `100` most recently used queries.
|
387
507
|
|
388
|
-
|
508
|
+
The cache size can be configured via `database.yml`
|
389
509
|
|
390
|
-
|
510
|
+
```yaml
|
511
|
+
development:
|
512
|
+
adapter: mysql2
|
513
|
+
query_cache: 200
|
514
|
+
```
|
391
515
|
|
392
|
-
|
516
|
+
It can also be entirely disabled:
|
393
517
|
|
394
|
-
|
518
|
+
```yaml
|
519
|
+
development:
|
520
|
+
adapter: mysql2
|
521
|
+
query_cache: false
|
522
|
+
```
|
395
523
|
|
396
|
-
*
|
524
|
+
*Jean Boussier*
|
397
525
|
|
398
|
-
|
526
|
+
* Deprecate `check_pending!` in favor of `check_all_pending!`.
|
399
527
|
|
400
|
-
|
528
|
+
`check_pending!` will only check for pending migrations on the current database connection or the one passed in. This has been deprecated in favor of `check_all_pending!` which will find all pending migrations for the database configurations in a given environment.
|
401
529
|
|
402
530
|
*Eileen M. Uchitelle*
|
403
531
|
|
532
|
+
* Make `increment_counter`/`decrement_counter` accept an amount argument
|
404
533
|
|
405
|
-
|
534
|
+
```ruby
|
535
|
+
Post.increment_counter(:comments_count, 5, by: 3)
|
536
|
+
```
|
406
537
|
|
407
|
-
*
|
538
|
+
*fatkodima*
|
408
539
|
|
409
|
-
|
540
|
+
* Add support for `Array#intersect?` to `ActiveRecord::Relation`.
|
410
541
|
|
411
|
-
|
542
|
+
`Array#intersect?` is only available on Ruby 3.1 or later.
|
412
543
|
|
413
|
-
|
544
|
+
This allows the Rubocop `Style/ArrayIntersect` cop to work with `ActiveRecord::Relation` objects.
|
414
545
|
|
415
|
-
*
|
546
|
+
*John Harry Kelly*
|
416
547
|
|
417
|
-
|
548
|
+
* The deferrable foreign key can be passed to `t.references`.
|
418
549
|
|
419
|
-
*
|
550
|
+
*Hiroyuki Ishii*
|
420
551
|
|
421
|
-
|
552
|
+
* Deprecate `deferrable: true` option of `add_foreign_key`.
|
422
553
|
|
423
|
-
|
554
|
+
`deferrable: true` is deprecated in favor of `deferrable: :immediate`, and
|
555
|
+
will be removed in Rails 7.2.
|
424
556
|
|
425
|
-
|
557
|
+
Because `deferrable: true` and `deferrable: :deferred` are hard to understand.
|
558
|
+
Both true and :deferred are truthy values.
|
559
|
+
This behavior is the same as the deferrable option of the add_unique_key method, added in #46192.
|
426
560
|
|
427
|
-
*
|
561
|
+
*Hiroyuki Ishii*
|
428
562
|
|
429
|
-
|
563
|
+
* `AbstractAdapter#execute` and `#exec_query` now clear the query cache
|
430
564
|
|
431
|
-
|
565
|
+
If you need to perform a read only SQL query without clearing the query
|
566
|
+
cache, use `AbstractAdapter#select_all`.
|
432
567
|
|
433
|
-
*
|
568
|
+
*Jean Boussier*
|
434
569
|
|
435
|
-
*
|
570
|
+
* Make `.joins` / `.left_outer_joins` work with CTEs.
|
436
571
|
|
437
|
-
|
572
|
+
For example:
|
438
573
|
|
439
|
-
|
574
|
+
```ruby
|
575
|
+
Post
|
576
|
+
.with(commented_posts: Comment.select(:post_id).distinct)
|
577
|
+
.joins(:commented_posts)
|
578
|
+
#=> WITH (...) SELECT ... INNER JOIN commented_posts on posts.id = commented_posts.post_id
|
579
|
+
```
|
440
580
|
|
441
|
-
*
|
581
|
+
*Vladimir Dementyev*
|
442
582
|
|
443
|
-
*
|
583
|
+
* Add a load hook for `ActiveRecord::ConnectionAdapters::Mysql2Adapter`
|
584
|
+
(named `active_record_mysql2adapter`) to allow for overriding aspects of the
|
585
|
+
`ActiveRecord::ConnectionAdapters::Mysql2Adapter` class. This makes `Mysql2Adapter`
|
586
|
+
consistent with `PostgreSQLAdapter` and `SQLite3Adapter` that already have load hooks.
|
444
587
|
|
445
|
-
|
446
|
-
to throw an error saying :polymorphic would not be a valid option.
|
588
|
+
*fatkodima*
|
447
589
|
|
448
|
-
|
590
|
+
* Introduce adapter for Trilogy database client
|
449
591
|
|
450
|
-
|
592
|
+
Trilogy is a MySQL-compatible database client. Rails applications can use Trilogy
|
593
|
+
by configuring their `config/database.yml`:
|
451
594
|
|
452
|
-
|
595
|
+
```yaml
|
596
|
+
development:
|
597
|
+
adapter: trilogy
|
598
|
+
database: blog_development
|
599
|
+
pool: 5
|
600
|
+
```
|
453
601
|
|
454
|
-
|
455
|
-
and the index name should be specified explicitly. Now, the index name is inferred
|
456
|
-
automatically.
|
602
|
+
Or by using the `DATABASE_URL` environment variable:
|
457
603
|
|
458
604
|
```ruby
|
459
|
-
|
605
|
+
ENV['DATABASE_URL'] # => "trilogy://localhost/blog_development?pool=5"
|
460
606
|
```
|
461
607
|
|
462
|
-
*
|
608
|
+
*Adrianna Chang*
|
463
609
|
|
610
|
+
* `after_commit` callbacks defined on models now execute in the correct order.
|
464
611
|
|
465
|
-
|
612
|
+
```ruby
|
613
|
+
class User < ActiveRecord::Base
|
614
|
+
after_commit { puts("this gets called first") }
|
615
|
+
after_commit { puts("this gets called second") }
|
616
|
+
end
|
617
|
+
```
|
466
618
|
|
467
|
-
|
619
|
+
Previously, the callbacks executed in the reverse order. To opt in to the new behaviour:
|
620
|
+
|
621
|
+
```ruby
|
622
|
+
config.active_record.run_after_transaction_callbacks_in_order_defined = true
|
623
|
+
```
|
468
624
|
|
469
|
-
|
625
|
+
This is the default for new apps.
|
470
626
|
|
471
627
|
*Alex Ghiculescu*
|
472
628
|
|
473
|
-
*
|
629
|
+
* Infer `foreign_key` when `inverse_of` is present on `has_one` and `has_many` associations.
|
474
630
|
|
475
|
-
|
631
|
+
```ruby
|
632
|
+
has_many :citations, foreign_key: "book1_id", inverse_of: :book
|
633
|
+
```
|
634
|
+
|
635
|
+
can be simplified to
|
636
|
+
|
637
|
+
```ruby
|
638
|
+
has_many :citations, inverse_of: :book
|
639
|
+
```
|
640
|
+
|
641
|
+
and the foreign_key will be read from the corresponding `belongs_to` association.
|
642
|
+
|
643
|
+
*Daniel Whitney*
|
644
|
+
|
645
|
+
* Limit max length of auto generated index names
|
646
|
+
|
647
|
+
Auto generated index names are now limited to 62 bytes, which fits within
|
648
|
+
the default index name length limits for MySQL, Postgres and SQLite.
|
649
|
+
|
650
|
+
Any index name over the limit will fallback to the new short format.
|
651
|
+
|
652
|
+
Before (too long):
|
653
|
+
```
|
654
|
+
index_testings_on_foo_and_bar_and_first_name_and_last_name_and_administrator
|
655
|
+
```
|
476
656
|
|
477
|
-
|
657
|
+
After (short format):
|
658
|
+
```
|
659
|
+
idx_on_foo_bar_first_name_last_name_administrator_5939248142
|
660
|
+
```
|
661
|
+
|
662
|
+
The short format includes a hash to ensure the name is unique database-wide.
|
478
663
|
|
479
|
-
|
664
|
+
*Mike Coutermarsh*
|
480
665
|
|
481
|
-
|
666
|
+
* Introduce a more stable and optimized Marshal serializer for Active Record models.
|
667
|
+
|
668
|
+
Can be enabled with `config.active_record.marshalling_format_version = 7.1`.
|
669
|
+
|
670
|
+
*Jean Boussier*
|
482
671
|
|
483
|
-
*
|
672
|
+
* Allow specifying where clauses with column-tuple syntax.
|
673
|
+
|
674
|
+
Querying through `#where` now accepts a new tuple-syntax which accepts, as
|
675
|
+
a key, an array of columns and, as a value, an array of corresponding tuples.
|
676
|
+
The key specifies a list of columns, while the value is an array of
|
677
|
+
ordered-tuples that conform to the column list.
|
678
|
+
|
679
|
+
For instance:
|
484
680
|
|
485
681
|
```ruby
|
486
|
-
|
487
|
-
|
682
|
+
# Cpk::Book => Cpk::Book(author_id: integer, number: integer, title: string, revision: integer)
|
683
|
+
# Cpk::Book.primary_key => ["author_id", "number"]
|
488
684
|
|
489
|
-
|
490
|
-
|
491
|
-
|
685
|
+
book = Cpk::Book.create!(author_id: 1, number: 1)
|
686
|
+
Cpk::Book.where(Cpk::Book.primary_key => [[1, 2]]) # => [book]
|
687
|
+
|
688
|
+
# Topic => Topic(id: integer, title: string, author_name: string...)
|
689
|
+
|
690
|
+
Topic.where([:title, :author_name] => [["The Alchemist", "Paulo Coelho"], ["Harry Potter", "J.K Rowling"]])
|
691
|
+
```
|
692
|
+
|
693
|
+
*Paarth Madan*
|
694
|
+
|
695
|
+
* Allow warning codes to be ignore when reporting SQL warnings.
|
696
|
+
|
697
|
+
Active Record config that can ignore warning codes
|
698
|
+
|
699
|
+
```ruby
|
700
|
+
# Configure allowlist of warnings that should always be ignored
|
701
|
+
config.active_record.db_warnings_ignore = [
|
702
|
+
"1062", # MySQL Error 1062: Duplicate entry
|
703
|
+
]
|
704
|
+
```
|
705
|
+
|
706
|
+
This is supported for the MySQL and PostgreSQL adapters.
|
707
|
+
|
708
|
+
*Nick Borromeo*
|
709
|
+
|
710
|
+
* Introduce `:active_record_fixtures` lazy load hook.
|
711
|
+
|
712
|
+
Hooks defined with this name will be run whenever `TestFixtures` is included
|
713
|
+
in a class.
|
714
|
+
|
715
|
+
```ruby
|
716
|
+
ActiveSupport.on_load(:active_record_fixtures) do
|
717
|
+
self.fixture_paths << "test/fixtures"
|
492
718
|
end
|
493
719
|
|
494
|
-
|
720
|
+
klass = Class.new
|
721
|
+
klass.include(ActiveRecord::TestFixtures)
|
722
|
+
|
723
|
+
klass.fixture_paths # => ["test/fixtures"]
|
495
724
|
```
|
496
725
|
|
497
|
-
*
|
726
|
+
*Andrew Novoselac*
|
498
727
|
|
499
|
-
*
|
728
|
+
* Introduce `TestFixtures#fixture_paths`.
|
500
729
|
|
501
|
-
|
730
|
+
Multiple fixture paths can now be specified using the `#fixture_paths` accessor.
|
731
|
+
Apps will continue to have `test/fixtures` as their one fixture path by default,
|
732
|
+
but additional fixture paths can be specified.
|
502
733
|
|
503
|
-
|
734
|
+
```ruby
|
735
|
+
ActiveSupport::TestCase.fixture_paths << "component1/test/fixtures"
|
736
|
+
ActiveSupport::TestCase.fixture_paths << "component2/test/fixtures"
|
737
|
+
```
|
504
738
|
|
505
|
-
|
506
|
-
MealsRecord.connected_to(role: :reading) do
|
507
|
-
Dog.first # read from animals replica
|
508
|
-
Dinner.first # read from meals replica
|
509
|
-
Person.first # read from primary writer
|
510
|
-
end
|
511
|
-
end
|
739
|
+
`TestFixtures#fixture_path` is now deprecated.
|
512
740
|
|
513
|
-
|
741
|
+
*Andrew Novoselac*
|
514
742
|
|
515
|
-
|
516
|
-
Dog.first # read from animals replica
|
517
|
-
Dinner.first # read from meals replica
|
518
|
-
Person.first # read from primary writer
|
519
|
-
end
|
743
|
+
* Adds support for deferrable exclude constraints in PostgreSQL.
|
520
744
|
|
521
|
-
|
745
|
+
By default, exclude constraints in PostgreSQL are checked after each statement.
|
746
|
+
This works for most use cases, but becomes a major limitation when replacing
|
747
|
+
records with overlapping ranges by using multiple statements.
|
522
748
|
|
523
|
-
|
749
|
+
```ruby
|
750
|
+
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :immediate
|
751
|
+
```
|
524
752
|
|
525
|
-
|
753
|
+
Passing `deferrable: :immediate` checks constraint after each statement,
|
754
|
+
but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED`
|
755
|
+
within a transaction. This will cause the excludes to be checked after the transaction.
|
526
756
|
|
527
|
-
|
757
|
+
It's also possible to change the default behavior from an immediate check
|
758
|
+
(after the statement), to a deferred check (after the transaction):
|
528
759
|
|
529
|
-
|
760
|
+
```ruby
|
761
|
+
exclusion_constraint :users, "daterange(valid_from, valid_to) WITH &&", deferrable: :deferred
|
762
|
+
```
|
530
763
|
|
531
|
-
*
|
764
|
+
*Hiroyuki Ishii*
|
532
765
|
|
533
|
-
|
766
|
+
* Respect `foreign_type` option to `delegated_type` for `{role}_class` method.
|
534
767
|
|
535
|
-
|
768
|
+
Usage of `delegated_type` with non-conventional `{role}_type` column names can now be specified with `foreign_type` option.
|
769
|
+
This option is the same as `foreign_type` as forwarded to the underlying `belongs_to` association that `delegated_type` wraps.
|
536
770
|
|
537
|
-
*
|
771
|
+
*Jason Karns*
|
538
772
|
|
539
|
-
|
773
|
+
* Add support for unique constraints (PostgreSQL-only).
|
540
774
|
|
541
|
-
|
775
|
+
```ruby
|
776
|
+
add_unique_key :sections, [:position], deferrable: :deferred, name: "unique_section_position"
|
777
|
+
remove_unique_key :sections, name: "unique_section_position"
|
778
|
+
```
|
542
779
|
|
543
|
-
|
780
|
+
See PostgreSQL's [Unique Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS) documentation for more on unique constraints.
|
544
781
|
|
545
|
-
|
782
|
+
By default, unique constraints in PostgreSQL are checked after each statement.
|
783
|
+
This works for most use cases, but becomes a major limitation when replacing
|
784
|
+
records with unique column by using multiple statements.
|
546
785
|
|
547
|
-
|
548
|
-
no longer enforce case sensitive comparison by default.
|
786
|
+
An example of swapping unique columns between records.
|
549
787
|
|
550
|
-
|
788
|
+
```ruby
|
789
|
+
# position is unique column
|
790
|
+
old_item = Item.create!(position: 1)
|
791
|
+
new_item = Item.create!(position: 2)
|
551
792
|
|
552
|
-
|
793
|
+
Item.transaction do
|
794
|
+
old_item.update!(position: 2)
|
795
|
+
new_item.update!(position: 1)
|
796
|
+
end
|
797
|
+
```
|
553
798
|
|
554
|
-
|
555
|
-
`
|
556
|
-
`columns_per_table`
|
557
|
-
`indexes_per_table`
|
558
|
-
`columns_per_multicolumn_index`
|
559
|
-
`sql_query_length`
|
560
|
-
`joins_per_query`
|
799
|
+
Using the default behavior, the transaction would fail when executing the
|
800
|
+
first `UPDATE` statement.
|
561
801
|
|
562
|
-
|
802
|
+
By passing the `:deferrable` option to the `add_unique_key` statement in
|
803
|
+
migrations, it's possible to defer this check.
|
563
804
|
|
564
|
-
|
805
|
+
```ruby
|
806
|
+
add_unique_key :items, [:position], deferrable: :immediate
|
807
|
+
```
|
565
808
|
|
566
|
-
|
809
|
+
Passing `deferrable: :immediate` does not change the behaviour of the previous example,
|
810
|
+
but allows manually deferring the check using `SET CONSTRAINTS ALL DEFERRED` within a transaction.
|
811
|
+
This will cause the unique constraints to be checked after the transaction.
|
567
812
|
|
568
|
-
|
813
|
+
It's also possible to adjust the default behavior from an immediate
|
814
|
+
check (after the statement), to a deferred check (after the transaction):
|
569
815
|
|
570
|
-
|
816
|
+
```ruby
|
817
|
+
add_unique_key :items, [:position], deferrable: :deferred
|
818
|
+
```
|
571
819
|
|
572
|
-
|
820
|
+
If you want to change an existing unique index to deferrable, you can use :using_index
|
821
|
+
to create deferrable unique constraints.
|
573
822
|
|
574
|
-
|
823
|
+
```ruby
|
824
|
+
add_unique_key :items, deferrable: :deferred, using_index: "index_items_on_position"
|
825
|
+
```
|
575
826
|
|
576
|
-
*
|
827
|
+
*Hiroyuki Ishii*
|
828
|
+
|
829
|
+
* Remove deprecated `Tasks::DatabaseTasks.schema_file_type`.
|
577
830
|
|
578
831
|
*Rafael Mendonça França*
|
579
832
|
|
580
|
-
* Remove deprecated `
|
833
|
+
* Remove deprecated `config.active_record.partial_writes`.
|
581
834
|
|
582
835
|
*Rafael Mendonça França*
|
583
836
|
|
584
|
-
* Remove deprecated `config.
|
837
|
+
* Remove deprecated `ActiveRecord::Base` config accessors.
|
585
838
|
|
586
839
|
*Rafael Mendonça França*
|
587
840
|
|
588
|
-
*
|
589
|
-
in initialization block and callbacks.
|
841
|
+
* Remove the `:include_replicas` argument from `configs_for`. Use `:include_hidden` argument instead.
|
590
842
|
|
591
|
-
|
843
|
+
*Eileen M. Uchitelle*
|
592
844
|
|
593
|
-
|
594
|
-
User.find_by(name: "David") # => nil
|
595
|
-
end
|
845
|
+
* Allow applications to lookup a config via a custom hash key.
|
596
846
|
|
597
|
-
|
847
|
+
If you have registered a custom config or want to find configs where the hash matches a specific key, now you can pass `config_key` to `configs_for`. For example if you have a `db_config` with the key `vitess` you can look up a database configuration hash by matching that key.
|
598
848
|
|
599
|
-
|
600
|
-
|
601
|
-
|
849
|
+
```ruby
|
850
|
+
ActiveRecord::Base.configurations.configs_for(env_name: "development", name: "primary", config_key: :vitess)
|
851
|
+
ActiveRecord::Base.configurations.configs_for(env_name: "development", config_key: :vitess)
|
852
|
+
```
|
602
853
|
|
603
|
-
*
|
854
|
+
*Eileen M. Uchitelle*
|
855
|
+
|
856
|
+
* Allow applications to register a custom database configuration handler.
|
857
|
+
|
858
|
+
Adds a mechanism for registering a custom handler for cases where you want database configurations to respond to custom methods. This is useful for non-Rails database adapters or tools like Vitess that you may want to configure differently from a standard `HashConfig` or `UrlConfig`.
|
859
|
+
|
860
|
+
Given the following database YAML we want the `animals` db to create a `CustomConfig` object instead while the `primary` database will be a `UrlConfig`:
|
861
|
+
|
862
|
+
```yaml
|
863
|
+
development:
|
864
|
+
primary:
|
865
|
+
url: postgres://localhost/primary
|
866
|
+
animals:
|
867
|
+
url: postgres://localhost/animals
|
868
|
+
custom_config:
|
869
|
+
sharded: 1
|
870
|
+
```
|
604
871
|
|
605
|
-
|
872
|
+
To register a custom handler first make a class that has your custom methods:
|
606
873
|
|
607
|
-
|
608
|
-
|
874
|
+
```ruby
|
875
|
+
class CustomConfig < ActiveRecord::DatabaseConfigurations::UrlConfig
|
876
|
+
def sharded?
|
877
|
+
custom_config.fetch("sharded", false)
|
878
|
+
end
|
879
|
+
|
880
|
+
private
|
881
|
+
def custom_config
|
882
|
+
configuration_hash.fetch(:custom_config)
|
609
883
|
end
|
884
|
+
end
|
885
|
+
```
|
610
886
|
|
611
|
-
|
887
|
+
Then register the config in an initializer:
|
612
888
|
|
613
|
-
|
614
|
-
|
889
|
+
```ruby
|
890
|
+
ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, url, config|
|
891
|
+
next unless config.key?(:custom_config)
|
892
|
+
CustomConfig.new(env_name, name, url, config)
|
893
|
+
end
|
894
|
+
```
|
615
895
|
|
616
|
-
|
896
|
+
When the application is booted, configuration hashes with the `:custom_config` key will be `CustomConfig` objects and respond to `sharded?`. Applications must handle the condition in which Active Record should use their custom handler.
|
617
897
|
|
618
|
-
|
619
|
-
# SELECT * FROM users WHERE name = 'David'
|
898
|
+
*Eileen M. Uchitelle and John Crepezzi*
|
620
899
|
|
621
|
-
|
900
|
+
* `ActiveRecord::Base.serialize` no longer uses YAML by default.
|
622
901
|
|
623
|
-
|
902
|
+
YAML isn't particularly performant and can lead to security issues
|
903
|
+
if not used carefully.
|
624
904
|
|
625
|
-
|
626
|
-
|
627
|
-
`first`
|
628
|
-
`values`
|
629
|
-
`[]=`
|
905
|
+
Unfortunately there isn't really any good serializers in Ruby's stdlib
|
906
|
+
to replace it.
|
630
907
|
|
631
|
-
|
908
|
+
The obvious choice would be JSON, which is a fine format for this use case,
|
909
|
+
however the JSON serializer in Ruby's stdlib isn't strict enough, as it fallback
|
910
|
+
to casting unknown types to strings, which could lead to corrupted data.
|
632
911
|
|
633
|
-
|
912
|
+
Some third party JSON libraries like `Oj` have a suitable strict mode.
|
634
913
|
|
635
|
-
|
914
|
+
So it's preferable that users choose a serializer based on their own constraints.
|
636
915
|
|
637
|
-
|
638
|
-
# SELECT * FROM users WHERE name != 'Jon' AND role != 'admin'
|
916
|
+
The original default can be restored by setting `config.active_record.default_column_serializer = YAML`.
|
639
917
|
|
640
|
-
|
918
|
+
*Jean Boussier*
|
641
919
|
|
642
|
-
|
643
|
-
# SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
|
920
|
+
* `ActiveRecord::Base.serialize` signature changed.
|
644
921
|
|
645
|
-
|
922
|
+
Rather than a single positional argument that accepts two possible
|
923
|
+
types of values, `serialize` now accepts two distinct keyword arguments.
|
646
924
|
|
647
|
-
|
925
|
+
Before:
|
648
926
|
|
649
|
-
|
927
|
+
```ruby
|
928
|
+
serialize :content, JSON
|
929
|
+
serialize :backtrace, Array
|
930
|
+
```
|
650
931
|
|
651
|
-
|
932
|
+
After:
|
652
933
|
|
653
|
-
|
934
|
+
```ruby
|
935
|
+
serialize :content, coder: JSON
|
936
|
+
serialize :backtrace, type: Array
|
937
|
+
```
|
654
938
|
|
655
|
-
*
|
939
|
+
*Jean Boussier*
|
656
940
|
|
657
|
-
|
941
|
+
* YAML columns use `YAML.safe_dump` if available.
|
658
942
|
|
659
|
-
|
660
|
-
|
943
|
+
As of `psych 5.1.0`, `YAML.safe_dump` can now apply the same permitted
|
944
|
+
types restrictions than `YAML.safe_load`.
|
661
945
|
|
662
|
-
|
946
|
+
It's preferable to ensure the payload only use allowed types when we first
|
947
|
+
try to serialize it, otherwise you may end up with invalid records in the
|
948
|
+
database.
|
663
949
|
|
664
|
-
*
|
950
|
+
*Jean Boussier*
|
665
951
|
|
666
|
-
|
952
|
+
* `ActiveRecord::QueryLogs` better handle broken encoding.
|
667
953
|
|
668
|
-
|
954
|
+
It's not uncommon when building queries with BLOB fields to contain
|
955
|
+
binary data. Unless the call carefully encode the string in ASCII-8BIT
|
956
|
+
it generally end up being encoded in `UTF-8`, and `QueryLogs` would
|
957
|
+
end up failing on it.
|
669
958
|
|
670
|
-
|
959
|
+
`ActiveRecord::QueryLogs` no longer depend on the query to be properly encoded.
|
671
960
|
|
672
|
-
|
673
|
-
ActiveRecord::Base.connected_to(role: :reading) do
|
674
|
-
User.first # reads from default replica
|
675
|
-
Dog.first # reads from default replica
|
961
|
+
*Jean Boussier*
|
676
962
|
|
677
|
-
|
678
|
-
User.first # reads from default replica
|
679
|
-
Dog.first # reads from shard one primary
|
680
|
-
end
|
963
|
+
* Fix a bug where `ActiveRecord::Generators::ModelGenerator` would not respect create_table_migration template overrides.
|
681
964
|
|
682
|
-
|
683
|
-
|
965
|
+
```
|
966
|
+
rails g model create_books title:string content:text
|
967
|
+
```
|
968
|
+
will now read from the create_table_migration.rb.tt template in the following locations in order:
|
969
|
+
```
|
970
|
+
lib/templates/active_record/model/create_table_migration.rb
|
971
|
+
lib/templates/active_record/migration/create_table_migration.rb
|
972
|
+
```
|
684
973
|
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
974
|
+
*Spencer Neste*
|
975
|
+
|
976
|
+
* `ActiveRecord::Relation#explain` now accepts options.
|
977
|
+
|
978
|
+
For databases and adapters which support them (currently PostgreSQL
|
979
|
+
and MySQL), options can be passed to `explain` to provide more
|
980
|
+
detailed query plan analysis:
|
981
|
+
|
982
|
+
```ruby
|
983
|
+
Customer.where(id: 1).joins(:orders).explain(:analyze, :verbose)
|
690
984
|
```
|
691
985
|
|
692
|
-
*
|
986
|
+
*Reid Lynch*
|
987
|
+
|
988
|
+
* Multiple `Arel::Nodes::SqlLiteral` nodes can now be added together to
|
989
|
+
form `Arel::Nodes::Fragments` nodes. This allows joining several pieces
|
990
|
+
of SQL.
|
991
|
+
|
992
|
+
*Matthew Draper*, *Ole Friis*
|
693
993
|
|
694
|
-
*
|
994
|
+
* `ActiveRecord::Base#signed_id` raises if called on a new record.
|
695
995
|
|
696
|
-
|
996
|
+
Previously it would return an ID that was not usable, since it was based on `id = nil`.
|
997
|
+
|
998
|
+
*Alex Ghiculescu*
|
697
999
|
|
698
|
-
*
|
1000
|
+
* Allow SQL warnings to be reported.
|
699
1001
|
|
700
|
-
|
1002
|
+
Active Record configs can be set to enable SQL warning reporting.
|
701
1003
|
|
702
1004
|
```ruby
|
703
|
-
|
704
|
-
|
705
|
-
|
1005
|
+
# Configure action to take when SQL query produces warning
|
1006
|
+
config.active_record.db_warnings_action = :raise
|
1007
|
+
|
1008
|
+
# Configure allowlist of warnings that should always be ignored
|
1009
|
+
config.active_record.db_warnings_ignore = [
|
1010
|
+
/Invalid utf8mb4 character string/,
|
1011
|
+
"An exact warning message",
|
1012
|
+
]
|
706
1013
|
```
|
707
1014
|
|
708
|
-
|
1015
|
+
This is supported for the MySQL and PostgreSQL adapters.
|
709
1016
|
|
710
|
-
*
|
1017
|
+
*Adrianna Chang*, *Paarth Madan*
|
711
1018
|
|
712
|
-
*
|
1019
|
+
* Add `#regroup` query method as a short-hand for `.unscope(:group).group(fields)`
|
713
1020
|
|
714
|
-
|
715
|
-
|
716
|
-
* Support passing record to uniqueness validator `:conditions` callable:
|
1021
|
+
Example:
|
717
1022
|
|
718
1023
|
```ruby
|
719
|
-
|
720
|
-
|
721
|
-
published_at = article.published_at
|
722
|
-
where(published_at: published_at.beginning_of_year..published_at.end_of_year)
|
723
|
-
}
|
724
|
-
end
|
1024
|
+
Post.group(:title).regroup(:author)
|
1025
|
+
# SELECT `posts`.`*` FROM `posts` GROUP BY `posts`.`author`
|
725
1026
|
```
|
726
1027
|
|
727
|
-
*
|
1028
|
+
*Danielius Visockas*
|
728
1029
|
|
729
|
-
*
|
730
|
-
|
1030
|
+
* PostgreSQL adapter method `enable_extension` now allows parameter to be `[schema_name.]<extension_name>`
|
1031
|
+
if the extension must be installed on another schema.
|
1032
|
+
|
1033
|
+
Example: `enable_extension('heroku_ext.hstore')`
|
1034
|
+
|
1035
|
+
*Leonardo Luarte*
|
1036
|
+
|
1037
|
+
* Add `:include` option to `add_index`.
|
1038
|
+
|
1039
|
+
Add support for including non-key columns in indexes for PostgreSQL
|
1040
|
+
with the `INCLUDE` parameter.
|
731
1041
|
|
732
1042
|
```ruby
|
733
|
-
|
734
|
-
Person.in_batches.delete_all # => 42
|
1043
|
+
add_index(:users, :email, include: [:id, :created_at])
|
735
1044
|
```
|
736
1045
|
|
737
|
-
|
1046
|
+
will result in:
|
738
1047
|
|
739
|
-
|
1048
|
+
```sql
|
1049
|
+
CREATE INDEX index_users_on_email USING btree (email) INCLUDE (id, created_at)
|
1050
|
+
```
|
740
1051
|
|
741
|
-
*
|
742
|
-
`ActiveSupport::Duration` when loading records from database and
|
743
|
-
serialization to ISO 8601 formatted duration string on save.
|
744
|
-
Add support to define a column in migrations and get it in a schema dump.
|
745
|
-
Optional column precision is supported.
|
1052
|
+
*Steve Abrams*
|
746
1053
|
|
747
|
-
|
1054
|
+
* `ActiveRecord::Relation`’s `#any?`, `#none?`, and `#one?` methods take an optional pattern
|
1055
|
+
argument, more closely matching their `Enumerable` equivalents.
|
748
1056
|
|
749
|
-
|
1057
|
+
*George Claghorn*
|
750
1058
|
|
751
|
-
|
1059
|
+
* Add `ActiveRecord::Base.normalizes` for declaring attribute normalizations.
|
752
1060
|
|
753
|
-
|
1061
|
+
An attribute normalization is applied when the attribute is assigned or
|
1062
|
+
updated, and the normalized value will be persisted to the database. The
|
1063
|
+
normalization is also applied to the corresponding keyword argument of query
|
1064
|
+
methods, allowing records to be queried using unnormalized values.
|
754
1065
|
|
755
|
-
|
1066
|
+
For example:
|
756
1067
|
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
1068
|
+
```ruby
|
1069
|
+
class User < ActiveRecord::Base
|
1070
|
+
normalizes :email, with: -> email { email.strip.downcase }
|
1071
|
+
normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") }
|
1072
|
+
end
|
761
1073
|
|
762
|
-
|
763
|
-
|
764
|
-
|
1074
|
+
user = User.create(email: " CRUISE-CONTROL@EXAMPLE.COM\n")
|
1075
|
+
user.email # => "cruise-control@example.com"
|
1076
|
+
|
1077
|
+
user = User.find_by(email: "\tCRUISE-CONTROL@EXAMPLE.COM ")
|
1078
|
+
user.email # => "cruise-control@example.com"
|
1079
|
+
user.email_before_type_cast # => "cruise-control@example.com"
|
1080
|
+
|
1081
|
+
User.where(email: "\tCRUISE-CONTROL@EXAMPLE.COM ").count # => 1
|
1082
|
+
User.where(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]).count # => 0
|
1083
|
+
|
1084
|
+
User.exists?(email: "\tCRUISE-CONTROL@EXAMPLE.COM ") # => true
|
1085
|
+
User.exists?(["email = ?", "\tCRUISE-CONTROL@EXAMPLE.COM "]) # => false
|
1086
|
+
|
1087
|
+
User.normalize_value_for(:phone, "+1 (555) 867-5309") # => "5558675309"
|
1088
|
+
```
|
1089
|
+
|
1090
|
+
*Jonathan Hefner*
|
765
1091
|
|
766
|
-
|
767
|
-
Event.last.duration # => 2 days
|
768
|
-
Event.last.duration.iso8601 # => "P2D"
|
769
|
-
Event.new(duration: 'P1DT12H3S').duration # => 1 day, 12 hours, and 3 seconds
|
770
|
-
Event.new(duration: '1 day') # Unknown value will be ignored and NULL will be written to database
|
1092
|
+
* Hide changes to before_committed! callback behaviour behind flag.
|
771
1093
|
|
772
|
-
|
1094
|
+
In #46525, behavior around before_committed! callbacks was changed so that callbacks
|
1095
|
+
would run on every enrolled record in a transaction, not just the first copy of a record.
|
1096
|
+
This change in behavior is now controlled by a configuration option,
|
1097
|
+
`config.active_record.before_committed_on_all_records`. It will be enabled by default on Rails 7.1.
|
773
1098
|
|
774
|
-
*
|
1099
|
+
*Adrianna Chang*
|
1100
|
+
|
1101
|
+
* The `namespaced_controller` Query Log tag now matches the `controller` format
|
1102
|
+
|
1103
|
+
For example, a request processed by `NameSpaced::UsersController` will now log as:
|
1104
|
+
|
1105
|
+
```
|
1106
|
+
:controller # "users"
|
1107
|
+
:namespaced_controller # "name_spaced/users"
|
1108
|
+
```
|
1109
|
+
|
1110
|
+
*Alex Ghiculescu*
|
1111
|
+
|
1112
|
+
* Return only unique ids from ActiveRecord::Calculations#ids
|
1113
|
+
|
1114
|
+
Updated ActiveRecord::Calculations#ids to only return the unique ids of the base model
|
1115
|
+
when using eager_load, preload and includes.
|
775
1116
|
|
776
1117
|
```ruby
|
777
|
-
|
778
|
-
|
779
|
-
|
1118
|
+
Post.find_by(id: 1).comments.count
|
1119
|
+
# => 5
|
1120
|
+
Post.includes(:comments).where(id: 1).pluck(:id)
|
1121
|
+
# => [1, 1, 1, 1, 1]
|
1122
|
+
Post.includes(:comments).where(id: 1).ids
|
1123
|
+
# => [1]
|
780
1124
|
```
|
781
1125
|
|
782
|
-
|
1126
|
+
*Joshua Young*
|
783
1127
|
|
784
|
-
|
1128
|
+
* Stop using `LOWER()` for case-insensitive queries on `citext` columns
|
785
1129
|
|
786
|
-
|
1130
|
+
Previously, `LOWER()` was added for e.g. uniqueness validations with
|
1131
|
+
`case_sensitive: false`.
|
1132
|
+
It wasn't mentioned in the documentation that the index without `LOWER()`
|
1133
|
+
wouldn't be used in this case.
|
787
1134
|
|
788
|
-
*
|
1135
|
+
*Phil Pirozhkov*
|
789
1136
|
|
790
|
-
* `
|
1137
|
+
* Extract `#sync_timezone_changes` method in AbstractMysqlAdapter to enable subclasses
|
1138
|
+
to sync database timezone changes without overriding `#raw_execute`.
|
791
1139
|
|
792
|
-
|
1140
|
+
*Adrianna Chang*, *Paarth Madan*
|
793
1141
|
|
794
|
-
|
1142
|
+
* Do not write additional new lines when dumping sql migration versions
|
795
1143
|
|
796
|
-
|
797
|
-
`ActiveRecord::StatementInvalid` when they encounter a connection error.
|
1144
|
+
This change updates the `insert_versions_sql` function so that the database insert string containing the current database migration versions does not end with two additional new lines.
|
798
1145
|
|
799
|
-
*
|
1146
|
+
*Misha Schwartz*
|
800
1147
|
|
801
|
-
* `
|
802
|
-
`ActiveRecord::StatementInvalid` when it can't connect to the MySQL server.
|
1148
|
+
* Fix `composed_of` value freezing and duplication.
|
803
1149
|
|
804
|
-
|
1150
|
+
Previously composite values exhibited two confusing behaviors:
|
805
1151
|
|
806
|
-
|
1152
|
+
- When reading a compositve value it'd _NOT_ be frozen, allowing it to get out of sync with its underlying database
|
1153
|
+
columns.
|
1154
|
+
- When writing a compositve value the argument would be frozen, potentially confusing the caller.
|
807
1155
|
|
808
|
-
|
1156
|
+
Currently, composite values instantiated based on database columns are frozen (addressing the first issue) and
|
1157
|
+
assigned compositve values are duplicated and the duplicate is frozen (addressing the second issue).
|
809
1158
|
|
810
|
-
*
|
1159
|
+
*Greg Navis*
|
811
1160
|
|
812
|
-
|
1161
|
+
* Fix redundant updates to the column insensitivity cache
|
813
1162
|
|
814
|
-
|
1163
|
+
Fixed redundant queries checking column capability for insensitive
|
1164
|
+
comparison.
|
815
1165
|
|
816
|
-
*
|
1166
|
+
*Phil Pirozhkov*
|
817
1167
|
|
818
|
-
|
819
|
-
class Comment < ActiveRecord::Base
|
820
|
-
enum label: [:default, :child]
|
821
|
-
has_many :children, class_name: "Comment", foreign_key: :parent_id
|
822
|
-
end
|
1168
|
+
* Allow disabling methods generated by `ActiveRecord.enum`.
|
823
1169
|
|
824
|
-
|
825
|
-
Comment.includes(:children).where("children.label": "child")
|
826
|
-
```
|
1170
|
+
*Alfred Dominic*
|
827
1171
|
|
828
|
-
|
1172
|
+
* Avoid validating `belongs_to` association if it has not changed.
|
829
1173
|
|
830
|
-
|
1174
|
+
Previously, when updating a record, Active Record will perform an extra query to check for the presence of
|
1175
|
+
`belongs_to` associations (if the presence is configured to be mandatory), even if that attribute hasn't changed.
|
831
1176
|
|
832
|
-
|
833
|
-
|
1177
|
+
Currently, only `belongs_to`-related columns are checked for presence. It is possible to have orphaned records with
|
1178
|
+
this approach. To avoid this problem, you need to use a foreign key.
|
834
1179
|
|
835
|
-
|
1180
|
+
This behavior can be controlled by configuration:
|
836
1181
|
|
837
|
-
|
1182
|
+
```ruby
|
1183
|
+
config.active_record.belongs_to_required_validates_foreign_key = false
|
1184
|
+
```
|
838
1185
|
|
839
|
-
|
840
|
-
`rails db:schema:{load, dump}` tasks to work with either `:ruby` or `:sql` format,
|
841
|
-
depending on `config.active_record.schema_format` configuration value.
|
1186
|
+
and will be disabled by default with `config.load_defaults 7.1`.
|
842
1187
|
|
843
1188
|
*fatkodima*
|
844
1189
|
|
845
|
-
*
|
1190
|
+
* `has_one` and `belongs_to` associations now define a `reset_association` method
|
1191
|
+
on the owner model (where `association` is the name of the association). This
|
1192
|
+
method unloads the cached associate record, if any, and causes the next access
|
1193
|
+
to query it from the database.
|
846
1194
|
|
847
|
-
|
848
|
-
post = Post.select("UPPER(title) AS title").first
|
849
|
-
post.title # => "WELCOME TO THE WEBLOG"
|
850
|
-
post.body # => ActiveModel::MissingAttributeError
|
1195
|
+
*George Claghorn*
|
851
1196
|
|
852
|
-
|
853
|
-
post = Post.select("UPPER(title) AS title").eager_load(:comments).first
|
854
|
-
post.title # => "Welcome to the weblog"
|
855
|
-
post.body # => "Such a lovely day"
|
1197
|
+
* Allow per attribute setting of YAML permitted classes (safe load) and unsafe load.
|
856
1198
|
|
857
|
-
|
858
|
-
post = Post.select("UPPER(title) AS title").eager_load(:comments).first
|
859
|
-
post.title # => "WELCOME TO THE WEBLOG"
|
860
|
-
post.body # => ActiveModel::MissingAttributeError
|
861
|
-
```
|
1199
|
+
*Carlos Palhares*
|
862
1200
|
|
863
|
-
|
1201
|
+
* Add a build persistence method
|
1202
|
+
|
1203
|
+
Provides a wrapper for `new`, to provide feature parity with `create`s
|
1204
|
+
ability to create multiple records from an array of hashes, using the
|
1205
|
+
same notation as the `build` method on associations.
|
1206
|
+
|
1207
|
+
*Sean Denny*
|
864
1208
|
|
865
|
-
*
|
1209
|
+
* Raise on assignment to readonly attributes
|
866
1210
|
|
867
1211
|
```ruby
|
868
1212
|
class Post < ActiveRecord::Base
|
869
|
-
|
1213
|
+
attr_readonly :content
|
870
1214
|
end
|
871
|
-
|
872
|
-
#
|
873
|
-
|
874
|
-
|
875
|
-
# Rails 6.1
|
876
|
-
Post.type_for_attribute(:written_at) # => #<Type::DateTime ... precision: 6, ...>
|
1215
|
+
Post.create!(content: "cannot be updated")
|
1216
|
+
post.content # "cannot be updated"
|
1217
|
+
post.content = "something else" # => ActiveRecord::ReadonlyAttributeError
|
877
1218
|
```
|
878
1219
|
|
879
|
-
|
1220
|
+
Previously, assignment would succeed but silently not write to the database.
|
880
1221
|
|
881
|
-
|
1222
|
+
This behavior can be controlled by configuration:
|
882
1223
|
|
883
1224
|
```ruby
|
884
|
-
|
885
|
-
enum status: [:proposed, :written, :published], _default: :published
|
886
|
-
end
|
887
|
-
|
888
|
-
Book.new.status # => "published"
|
1225
|
+
config.active_record.raise_on_assign_to_attr_readonly = true
|
889
1226
|
```
|
890
1227
|
|
891
|
-
|
1228
|
+
and will be enabled by default with `config.load_defaults 7.1`.
|
892
1229
|
|
893
|
-
*
|
1230
|
+
*Alex Ghiculescu*, *Hartley McGuire*
|
894
1231
|
|
895
|
-
|
1232
|
+
* Allow unscoping of preload and eager_load associations
|
896
1233
|
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
do not generally mutate string properties of Active Record objects.
|
1234
|
+
Added the ability to unscope preload and eager_load associations just like
|
1235
|
+
includes, joins, etc. See ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES
|
1236
|
+
for the full list of supported unscopable scopes.
|
901
1237
|
|
902
|
-
|
1238
|
+
```ruby
|
1239
|
+
query.unscope(:eager_load, :preload).group(:id).select(:id)
|
1240
|
+
```
|
903
1241
|
|
904
|
-
*
|
1242
|
+
*David Morehouse*
|
905
1243
|
|
906
|
-
|
1244
|
+
* Add automatic filtering of encrypted attributes on inspect
|
907
1245
|
|
908
|
-
|
1246
|
+
This feature is enabled by default but can be disabled with
|
909
1247
|
|
910
1248
|
```ruby
|
911
|
-
|
912
|
-
mary_and_bob = Author.where(id: [mary, bob])
|
913
|
-
|
914
|
-
david_and_mary.merge(mary_and_bob) # => [mary, bob]
|
915
|
-
|
916
|
-
david_and_mary.and(mary_and_bob) # => [mary]
|
917
|
-
david_and_mary.or(mary_and_bob) # => [david, mary, bob]
|
1249
|
+
config.active_record.encryption.add_to_filter_parameters = false
|
918
1250
|
```
|
919
1251
|
|
920
|
-
*
|
921
|
-
|
922
|
-
* Merging conditions on the same column no longer maintain both conditions,
|
923
|
-
and will be consistently replaced by the latter condition in Rails 7.0.
|
924
|
-
To migrate to Rails 7.0's behavior, use `relation.merge(other, rewhere: true)`.
|
925
|
-
|
926
|
-
```ruby
|
927
|
-
# Rails 6.1 (IN clause is replaced by merger side equality condition)
|
928
|
-
Author.where(id: [david.id, mary.id]).merge(Author.where(id: bob)) # => [bob]
|
1252
|
+
*Hartley McGuire*
|
929
1253
|
|
930
|
-
|
931
|
-
Author.where(id: david.id..mary.id).merge(Author.where(id: bob)) # => []
|
1254
|
+
* Clear locking column on #dup
|
932
1255
|
|
933
|
-
|
934
|
-
Author.where(id: david.id..mary.id).merge(Author.where(id: bob), rewhere: true) # => [bob]
|
1256
|
+
This change fixes not to duplicate locking_column like id and timestamps.
|
935
1257
|
|
936
|
-
|
937
|
-
|
938
|
-
|
1258
|
+
```
|
1259
|
+
car = Car.create!
|
1260
|
+
car.touch
|
1261
|
+
car.lock_version #=> 1
|
1262
|
+
car.dup.lock_version #=> 0
|
939
1263
|
```
|
940
1264
|
|
941
|
-
*
|
1265
|
+
*Shouichi Kamiya*, *Seonggi Yang*, *Ryohei UEDA*
|
942
1266
|
|
943
|
-
*
|
1267
|
+
* Invalidate transaction as early as possible
|
944
1268
|
|
945
|
-
|
1269
|
+
After rescuing a `TransactionRollbackError` exception Rails invalidates transactions earlier in the flow
|
1270
|
+
allowing the framework to skip issuing the `ROLLBACK` statement in more cases.
|
1271
|
+
Only affects adapters that have `savepoint_errors_invalidate_transactions?` configured as `true`,
|
1272
|
+
which at this point is only applicable to the `mysql2` adapter.
|
946
1273
|
|
947
|
-
*
|
1274
|
+
*Nikita Vasilevsky*
|
948
1275
|
|
949
|
-
|
950
|
-
`ActiveRecord::Persistence.upsert_all` was used with the name of an expression index, an error
|
951
|
-
was raised. Adding a guard around the formatting behavior for the `:unique_by` corrects this.
|
1276
|
+
* Allow configuring columns list to be used in SQL queries issued by an `ActiveRecord::Base` object
|
952
1277
|
|
953
|
-
|
1278
|
+
It is now possible to configure columns list that will be used to build an SQL query clauses when
|
1279
|
+
updating, deleting or reloading an `ActiveRecord::Base` object
|
954
1280
|
|
955
1281
|
```ruby
|
956
|
-
|
957
|
-
|
958
|
-
t.index "lower(name)", unique: true
|
1282
|
+
class Developer < ActiveRecord::Base
|
1283
|
+
query_constraints :company_id, :id
|
959
1284
|
end
|
960
|
-
|
961
|
-
|
1285
|
+
developer = Developer.first.update(name: "Bob")
|
1286
|
+
# => UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
962
1287
|
```
|
963
1288
|
|
964
|
-
|
1289
|
+
*Nikita Vasilevsky*
|
965
1290
|
|
966
|
-
|
1291
|
+
* Adds `validate` to foreign keys and check constraints in schema.rb
|
967
1292
|
|
968
|
-
|
1293
|
+
Previously, `schema.rb` would not record if `validate: false` had been used when adding a foreign key or check
|
1294
|
+
constraint, so restoring a database from the schema could result in foreign keys or check constraints being
|
1295
|
+
incorrectly validated.
|
969
1296
|
|
970
|
-
|
1297
|
+
*Tommy Graves*
|
971
1298
|
|
972
|
-
|
973
|
-
|
974
|
-
remove_check_constraint :products, name: "price_check"
|
975
|
-
```
|
1299
|
+
* Adapter `#execute` methods now accept an `allow_retry` option. When set to `true`, the SQL statement will be
|
1300
|
+
retried, up to the database's configured `connection_retries` value, upon encountering connection-related errors.
|
976
1301
|
|
977
|
-
*
|
1302
|
+
*Adrianna Chang*
|
978
1303
|
|
979
|
-
*
|
980
|
-
to enable/disable strict_loading mode by default for a model. The configuration's value is
|
981
|
-
inheritable by subclasses, but they can override that value and it will not impact parent class.
|
1304
|
+
* Only trigger `after_commit :destroy` callbacks when a database row is deleted.
|
982
1305
|
|
983
|
-
|
1306
|
+
This prevents `after_commit :destroy` callbacks from being triggered again
|
1307
|
+
when `destroy` is called multiple times on the same record.
|
984
1308
|
|
985
|
-
|
986
|
-
class Developer < ApplicationRecord
|
987
|
-
self.strict_loading_by_default = true
|
1309
|
+
*Ben Sheldon*
|
988
1310
|
|
989
|
-
|
990
|
-
end
|
1311
|
+
* Fix `ciphertext_for` for yet-to-be-encrypted values.
|
991
1312
|
|
992
|
-
|
993
|
-
|
994
|
-
# => ActiveRecord::StrictLoadingViolationError Exception: Developer is marked as strict_loading and Project cannot be lazily loaded.
|
995
|
-
```
|
1313
|
+
Previously, `ciphertext_for` returned the cleartext of values that had not
|
1314
|
+
yet been encrypted, such as with an unpersisted record:
|
996
1315
|
|
997
|
-
|
1316
|
+
```ruby
|
1317
|
+
Post.encrypts :body
|
998
1318
|
|
999
|
-
|
1319
|
+
post = Post.create!(body: "Hello")
|
1320
|
+
post.ciphertext_for(:body)
|
1321
|
+
# => "{\"p\":\"abc..."
|
1000
1322
|
|
1001
|
-
|
1323
|
+
post.body = "World"
|
1324
|
+
post.ciphertext_for(:body)
|
1325
|
+
# => "World"
|
1326
|
+
```
|
1002
1327
|
|
1003
|
-
|
1328
|
+
Now, `ciphertext_for` will always return the ciphertext of encrypted
|
1329
|
+
attributes:
|
1004
1330
|
|
1005
|
-
|
1331
|
+
```ruby
|
1332
|
+
Post.encrypts :body
|
1006
1333
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
```
|
1334
|
+
post = Post.create!(body: "Hello")
|
1335
|
+
post.ciphertext_for(:body)
|
1336
|
+
# => "{\"p\":\"abc..."
|
1011
1337
|
|
1012
|
-
|
1338
|
+
post.body = "World"
|
1339
|
+
post.ciphertext_for(:body)
|
1340
|
+
# => "{\"p\":\"xyz..."
|
1341
|
+
```
|
1013
1342
|
|
1014
|
-
|
1015
|
-
create_table "accounts", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
1016
|
-
end
|
1017
|
-
```
|
1343
|
+
*Jonathan Hefner*
|
1018
1344
|
|
1019
|
-
|
1345
|
+
* Fix a bug where using groups and counts with long table names would return incorrect results.
|
1020
1346
|
|
1021
|
-
*
|
1022
|
-
See ActiveRecord::DelegatedType for the full description.
|
1347
|
+
*Shota Toguchi*, *Yusaku Ono*
|
1023
1348
|
|
1024
|
-
|
1349
|
+
* Fix encryption of column default values.
|
1025
1350
|
|
1026
|
-
|
1351
|
+
Previously, encrypted attributes that used column default values appeared to
|
1352
|
+
be encrypted on create, but were not:
|
1027
1353
|
|
1028
|
-
|
1354
|
+
```ruby
|
1355
|
+
Book.encrypts :name
|
1029
1356
|
|
1030
|
-
|
1031
|
-
|
1357
|
+
book = Book.create!
|
1358
|
+
book.name
|
1359
|
+
# => "<untitled>"
|
1360
|
+
book.name_before_type_cast
|
1361
|
+
# => "{\"p\":\"abc..."
|
1362
|
+
book.reload.name_before_type_cast
|
1363
|
+
# => "<untitled>"
|
1364
|
+
```
|
1032
1365
|
|
1033
|
-
|
1034
|
-
accounts.merge(accounts.where.not(credit_limit: nil)).sum(:credit_limit)
|
1035
|
-
# => {
|
1036
|
-
# [1, 1] => 50,
|
1037
|
-
# [2, 2] => 60
|
1038
|
-
# }
|
1366
|
+
Now, attributes with column default values are encrypted:
|
1039
1367
|
|
1040
|
-
|
1041
|
-
|
1042
|
-
# => {
|
1043
|
-
# 1 => 50,
|
1044
|
-
# 2 => 60
|
1045
|
-
# }
|
1046
|
-
```
|
1368
|
+
```ruby
|
1369
|
+
Book.encrypts :name
|
1047
1370
|
|
1048
|
-
|
1371
|
+
book = Book.create!
|
1372
|
+
book.name
|
1373
|
+
# => "<untitled>"
|
1374
|
+
book.name_before_type_cast
|
1375
|
+
# => "{\"p\":\"abc..."
|
1376
|
+
book.reload.name_before_type_cast
|
1377
|
+
# => "{\"p\":\"abc..."
|
1378
|
+
```
|
1049
1379
|
|
1050
|
-
*
|
1380
|
+
*Jonathan Hefner*
|
1051
1381
|
|
1052
|
-
|
1382
|
+
* Deprecate delegation from `Base` to `connection_handler`.
|
1053
1383
|
|
1054
|
-
|
1055
|
-
accounts = Account.where(id: [1, 2]).annotate("david and mary")
|
1384
|
+
Calling `Base.clear_all_connections!`, `Base.clear_active_connections!`, `Base.clear_reloadable_connections!` and `Base.flush_idle_connections!` is deprecated. Please call these methods on the connection handler directly. In future Rails versions, the delegation from `Base` to the `connection_handler` will be removed.
|
1056
1385
|
|
1057
|
-
|
1058
|
-
accounts.merge(accounts.rewhere(id: 3))
|
1059
|
-
# SELECT accounts.* FROM accounts WHERE accounts.id = 3 /* david and mary */ /* david and mary */
|
1386
|
+
*Eileen M. Uchitelle*
|
1060
1387
|
|
1061
|
-
|
1062
|
-
accounts.merge(accounts.rewhere(id: 3)).uniq!(:annotate)
|
1063
|
-
# SELECT accounts.* FROM accounts WHERE accounts.id = 3 /* david and mary */
|
1064
|
-
```
|
1388
|
+
* Allow ActiveRecord::QueryMethods#reselect to receive hash values, similar to ActiveRecord::QueryMethods#select
|
1065
1389
|
|
1066
|
-
*
|
1390
|
+
*Sampat Badhe*
|
1067
1391
|
|
1068
|
-
*
|
1392
|
+
* Validate options when managing columns and tables in migrations.
|
1069
1393
|
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
database record's `lock_version` column.
|
1394
|
+
If an invalid option is passed to a migration method like `create_table` and `add_column`, an error will be raised
|
1395
|
+
instead of the option being silently ignored. Validation of the options will only be applied for new migrations
|
1396
|
+
that are created.
|
1074
1397
|
|
1075
|
-
|
1398
|
+
*Guo Xiang Tan*, *George Wambold*
|
1076
1399
|
|
1077
|
-
|
1400
|
+
* Update query log tags to use the [SQLCommenter](https://open-telemetry.github.io/opentelemetry-sqlcommenter/) format by default. See [#46179](https://github.com/rails/rails/issues/46179)
|
1078
1401
|
|
1079
|
-
|
1402
|
+
To opt out of SQLCommenter-formatted query log tags, set `config.active_record.query_log_tags_format = :legacy`. By default, this is set to `:sqlcommenter`.
|
1080
1403
|
|
1081
|
-
|
1082
|
-
david_and_mary = Author.where(id: david.id..mary.id)
|
1404
|
+
*Modulitos* and *Iheanyi*
|
1083
1405
|
|
1084
|
-
|
1085
|
-
david_and_mary.merge(Author.where(id: bob)) # => []
|
1406
|
+
* Allow any ERB in the database.yml when creating rake tasks.
|
1086
1407
|
|
1087
|
-
|
1088
|
-
|
1408
|
+
Any ERB can be used in `database.yml` even if it accesses environment
|
1409
|
+
configurations.
|
1089
1410
|
|
1090
|
-
|
1091
|
-
david_and_mary.merge(Author.where(id: bob), rewhere: true) # => [bob]
|
1092
|
-
```
|
1411
|
+
Deprecates `config.active_record.suppress_multiple_database_warning`.
|
1093
1412
|
|
1094
|
-
*
|
1413
|
+
*Eike Send*
|
1095
1414
|
|
1096
|
-
* Add
|
1097
|
-
set to expire and scoped with a purpose. This is particularly useful for things like password reset
|
1098
|
-
or email verification, where you want the bearer of the signed id to be able to interact with the
|
1099
|
-
underlying record, but usually only within a certain time period.
|
1415
|
+
* Add table to error for duplicate column definitions.
|
1100
1416
|
|
1101
|
-
|
1102
|
-
|
1417
|
+
If a migration defines duplicate columns for a table, the error message
|
1418
|
+
shows which table it concerns.
|
1103
1419
|
|
1104
|
-
|
1420
|
+
*Petrik de Heus*
|
1105
1421
|
|
1106
|
-
|
1107
|
-
User.find_signed signed_id, purpose: :password_reset # => nil, since the signed id has expired
|
1422
|
+
* Fix erroneous nil default precision on virtual datetime columns.
|
1108
1423
|
|
1109
|
-
|
1110
|
-
|
1424
|
+
Prior to this change, virtual datetime columns did not have the same
|
1425
|
+
default precision as regular datetime columns, resulting in the following
|
1426
|
+
being erroneously equivalent:
|
1111
1427
|
|
1112
|
-
|
1113
|
-
|
1428
|
+
t.virtual :name, type: datetime, as: "expression"
|
1429
|
+
t.virtual :name, type: datetime, precision: nil, as: "expression"
|
1114
1430
|
|
1115
|
-
|
1431
|
+
This change fixes the default precision lookup, so virtual and regular
|
1432
|
+
datetime column default precisions match.
|
1116
1433
|
|
1117
|
-
*
|
1434
|
+
*Sam Bostock*
|
1118
1435
|
|
1119
|
-
|
1436
|
+
* Use connection from `#with_raw_connection` in `#quote_string`.
|
1120
1437
|
|
1121
|
-
|
1438
|
+
This ensures that the string quoting is wrapped in the reconnect and retry logic
|
1439
|
+
that `#with_raw_connection` offers.
|
1122
1440
|
|
1123
|
-
*
|
1441
|
+
*Adrianna Chang*
|
1124
1442
|
|
1125
|
-
*
|
1443
|
+
* Add `expires_at` option to `signed_id`.
|
1126
1444
|
|
1127
|
-
|
1445
|
+
*Shouichi Kamiya*
|
1128
1446
|
|
1129
|
-
|
1130
|
-
posts = Post.joins(:comments).group(:"posts.hidden")
|
1131
|
-
posts = posts.where("posts.hidden": false, "comments.hidden": false)
|
1447
|
+
* Allow applications to set retry deadline for query retries.
|
1132
1448
|
|
1133
|
-
|
1134
|
-
|
1449
|
+
Building on the work done in #44576 and #44591, we extend the logic that automatically
|
1450
|
+
reconnects database connections to take into account a timeout limit. We won't retry
|
1451
|
+
a query if a given amount of time has elapsed since the query was first attempted. This
|
1452
|
+
value defaults to nil, meaning that all retryable queries are retried regardless of time elapsed,
|
1453
|
+
but this can be changed via the `retry_deadline` option in the database config.
|
1135
1454
|
|
1136
|
-
|
1137
|
-
posts.unscope(where: :hidden).count
|
1138
|
-
# => { false => 11, true => 1 }
|
1455
|
+
*Adrianna Chang*
|
1139
1456
|
|
1140
|
-
|
1141
|
-
posts.unscope(where: :"comments.hidden").count
|
1142
|
-
# => { false => 11 }
|
1143
|
-
```
|
1457
|
+
* Fix a case where the query cache can return wrong values. See #46044
|
1144
1458
|
|
1145
|
-
*
|
1459
|
+
*Aaron Patterson*
|
1146
1460
|
|
1147
|
-
*
|
1461
|
+
* Support MySQL's ssl-mode option for MySQLDatabaseTasks.
|
1148
1462
|
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1463
|
+
Verifying the identity of the database server requires setting the ssl-mode
|
1464
|
+
option to VERIFY_CA or VERIFY_IDENTITY. This option was previously ignored
|
1465
|
+
for MySQL database tasks like creating a database and dumping the structure.
|
1152
1466
|
|
1153
|
-
|
1467
|
+
*Petrik de Heus*
|
1154
1468
|
|
1155
|
-
|
1156
|
-
relation.rewhere(writer: david).to_a # => []
|
1469
|
+
* Move `ActiveRecord::InternalMetadata` to an independent object.
|
1157
1470
|
|
1158
|
-
|
1159
|
-
relation.rewhere(writer: david).to_a # => [david]
|
1160
|
-
```
|
1471
|
+
`ActiveRecord::InternalMetadata` no longer inherits from `ActiveRecord::Base` and is now an independent object that should be instantiated with a `connection`. This class is private and should not be used by applications directly. If you want to interact with the schema migrations table, please access it on the connection directly, for example: `ActiveRecord::Base.connection.schema_migration`.
|
1161
1472
|
|
1162
|
-
*
|
1473
|
+
*Eileen M. Uchitelle*
|
1163
1474
|
|
1164
|
-
*
|
1475
|
+
* Deprecate quoting `ActiveSupport::Duration` as an integer
|
1165
1476
|
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1477
|
+
Using ActiveSupport::Duration as an interpolated bind parameter in a SQL
|
1478
|
+
string template is deprecated. To avoid this warning, you should explicitly
|
1479
|
+
convert the duration to a more specific database type. For example, if you
|
1480
|
+
want to use a duration as an integer number of seconds:
|
1481
|
+
```
|
1482
|
+
Record.where("duration = ?", 1.hour.to_i)
|
1483
|
+
```
|
1484
|
+
If you want to use a duration as an ISO 8601 string:
|
1485
|
+
```
|
1486
|
+
Record.where("duration = ?", 1.hour.iso8601)
|
1169
1487
|
```
|
1170
1488
|
|
1171
|
-
*
|
1489
|
+
*Aram Greenman*
|
1172
1490
|
|
1173
|
-
*
|
1491
|
+
* Allow `QueryMethods#in_order_of` to order by a string column name.
|
1174
1492
|
|
1175
|
-
|
1493
|
+
```ruby
|
1494
|
+
Post.in_order_of("id", [4,2,3,1]).to_a
|
1495
|
+
Post.joins(:author).in_order_of("authors.name", ["Bob", "Anna", "John"]).to_a
|
1496
|
+
```
|
1176
1497
|
|
1177
|
-
*
|
1498
|
+
*Igor Kasyanchuk*
|
1178
1499
|
|
1179
|
-
|
1500
|
+
* Move `ActiveRecord::SchemaMigration` to an independent object.
|
1180
1501
|
|
1181
|
-
|
1502
|
+
`ActiveRecord::SchemaMigration` no longer inherits from `ActiveRecord::Base` and is now an independent object that should be instantiated with a `connection`. This class is private and should not be used by applications directly. If you want to interact with the schema migrations table, please access it on the connection directly, for example: `ActiveRecord::Base.connection.schema_migration`.
|
1182
1503
|
|
1183
|
-
*
|
1504
|
+
*Eileen M. Uchitelle*
|
1505
|
+
|
1506
|
+
* Deprecate `all_connection_pools` and make `connection_pool_list` more explicit.
|
1184
1507
|
|
1185
|
-
|
1508
|
+
Following on #45924 `all_connection_pools` is now deprecated. `connection_pool_list` will either take an explicit role or applications can opt into the new behavior by passing `:all`.
|
1186
1509
|
|
1187
|
-
*
|
1510
|
+
*Eileen M. Uchitelle*
|
1188
1511
|
|
1189
|
-
*
|
1512
|
+
* Fix connection handler methods to operate on all pools.
|
1190
1513
|
|
1191
|
-
|
1514
|
+
`active_connections?`, `clear_active_connections!`, `clear_reloadable_connections!`, `clear_all_connections!`, and `flush_idle_connections!` now operate on all pools by default. Previously they would default to using the `current_role` or `:writing` role unless specified.
|
1192
1515
|
|
1193
1516
|
*Eileen M. Uchitelle*
|
1194
1517
|
|
1195
|
-
* Remove ibm_db, informix, mssql, oracle, and oracle12 Arel visitors which are not used in the code base.
|
1196
1518
|
|
1197
|
-
|
1519
|
+
* Allow ActiveRecord::QueryMethods#select to receive hash values.
|
1198
1520
|
|
1199
|
-
|
1521
|
+
Currently, `select` might receive only raw sql and symbols to define columns and aliases to select.
|
1200
1522
|
|
1201
|
-
|
1523
|
+
With this change we can provide `hash` as argument, for example:
|
1202
1524
|
|
1203
|
-
|
1525
|
+
```ruby
|
1526
|
+
Post.joins(:comments).select(posts: [:id, :title, :created_at], comments: [:id, :body, :author_id])
|
1527
|
+
#=> "SELECT \"posts\".\"id\", \"posts\".\"title\", \"posts\".\"created_at\", \"comments\".\"id\", \"comments\".\"body\", \"comments\".\"author_id\"
|
1528
|
+
# FROM \"posts\" INNER JOIN \"comments\" ON \"comments\".\"post_id\" = \"posts\".\"id\""
|
1204
1529
|
|
1205
|
-
|
1530
|
+
Post.joins(:comments).select(posts: { id: :post_id, title: :post_title }, comments: { id: :comment_id, body: :comment_body })
|
1531
|
+
#=> "SELECT posts.id as post_id, posts.title as post_title, comments.id as comment_id, comments.body as comment_body
|
1532
|
+
# FROM \"posts\" INNER JOIN \"comments\" ON \"comments\".\"post_id\" = \"posts\".\"id\""
|
1533
|
+
```
|
1534
|
+
*Oleksandr Holubenko*, *Josef Šimánek*, *Jean Boussier*
|
1206
1535
|
|
1207
|
-
|
1208
|
-
index won't be added.
|
1536
|
+
* Adapts virtual attributes on `ActiveRecord::Persistence#becomes`.
|
1209
1537
|
|
1210
|
-
|
1538
|
+
When source and target classes have a different set of attributes adapts
|
1539
|
+
attributes such that the extra attributes from target are added.
|
1211
1540
|
|
1212
1541
|
```ruby
|
1213
|
-
|
1214
|
-
|
1542
|
+
class Person < ApplicationRecord
|
1543
|
+
end
|
1215
1544
|
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1545
|
+
class WebUser < Person
|
1546
|
+
attribute :is_admin, :boolean
|
1547
|
+
after_initialize :set_admin
|
1219
1548
|
|
1220
|
-
|
1549
|
+
def set_admin
|
1550
|
+
write_attribute(:is_admin, email =~ /@ourcompany\.com$/)
|
1551
|
+
end
|
1552
|
+
end
|
1221
1553
|
|
1222
|
-
|
1554
|
+
person = Person.find_by(email: "email@ourcompany.com")
|
1555
|
+
person.respond_to? :is_admin
|
1556
|
+
# => false
|
1557
|
+
person.becomes(WebUser).is_admin?
|
1558
|
+
# => true
|
1559
|
+
```
|
1223
1560
|
|
1224
|
-
*
|
1561
|
+
*Jacopo Beschi*, *Sampson Crowley*
|
1225
1562
|
|
1226
|
-
*
|
1563
|
+
* Fix `ActiveRecord::QueryMethods#in_order_of` to include `nil`s, to match the
|
1564
|
+
behavior of `Enumerable#in_order_of`.
|
1227
1565
|
|
1228
|
-
|
1566
|
+
For example, `Post.in_order_of(:title, [nil, "foo"])` will now include posts
|
1567
|
+
with `nil` titles, the same as `Post.all.to_a.in_order_of(:title, [nil, "foo"])`.
|
1229
1568
|
|
1230
|
-
|
1569
|
+
*fatkodima*
|
1231
1570
|
|
1232
|
-
|
1571
|
+
* Optimize `add_timestamps` to use a single SQL statement.
|
1233
1572
|
|
1234
1573
|
```ruby
|
1235
|
-
|
1236
|
-
person.party_all_night!
|
1237
|
-
end
|
1574
|
+
add_timestamps :my_table
|
1238
1575
|
```
|
1239
1576
|
|
1240
|
-
|
1241
|
-
|
1242
|
-
* Fix `insert_all` with enum values.
|
1577
|
+
Now results in the following SQL:
|
1243
1578
|
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1579
|
+
```sql
|
1580
|
+
ALTER TABLE "my_table" ADD COLUMN "created_at" datetime(6) NOT NULL, ADD COLUMN "updated_at" datetime(6) NOT NULL
|
1581
|
+
```
|
1247
1582
|
|
1248
|
-
*
|
1583
|
+
*Iliana Hadzhiatanasova*
|
1249
1584
|
|
1250
|
-
|
1585
|
+
* Add `drop_enum` migration command for PostgreSQL
|
1251
1586
|
|
1252
|
-
|
1587
|
+
This does the inverse of `create_enum`. Before dropping an enum, ensure you have
|
1588
|
+
dropped columns that depend on it.
|
1253
1589
|
|
1254
|
-
*
|
1590
|
+
*Alex Ghiculescu*
|
1255
1591
|
|
1256
|
-
|
1592
|
+
* Adds support for `if_exists` option when removing a check constraint.
|
1257
1593
|
|
1258
|
-
|
1594
|
+
The `remove_check_constraint` method now accepts an `if_exists` option. If set
|
1595
|
+
to true an error won't be raised if the check constraint doesn't exist.
|
1259
1596
|
|
1260
|
-
*
|
1597
|
+
*Margaret Parsa* and *Aditya Bhutani*
|
1261
1598
|
|
1262
|
-
*
|
1599
|
+
* `find_or_create_by` now try to find a second time if it hits a unicity constraint.
|
1263
1600
|
|
1264
|
-
|
1601
|
+
`find_or_create_by` always has been inherently racy, either creating multiple
|
1602
|
+
duplicate records or failing with `ActiveRecord::RecordNotUnique` depending on
|
1603
|
+
whether a proper unicity constraint was set.
|
1265
1604
|
|
1266
|
-
|
1605
|
+
`create_or_find_by` was introduced for this use case, however it's quite wasteful
|
1606
|
+
when the record is expected to exist most of the time, as INSERT require to send
|
1607
|
+
more data than SELECT and require more work from the database. Also on some
|
1608
|
+
databases it can actually consume a primary key increment which is undesirable.
|
1267
1609
|
|
1268
|
-
|
1610
|
+
So for case where most of the time the record is expected to exist, `find_or_create_by`
|
1611
|
+
can be made race-condition free by re-trying the `find` if the `create` failed
|
1612
|
+
with `ActiveRecord::RecordNotUnique`. This assumes that the table has the proper
|
1613
|
+
unicity constraints, if not, `find_or_create_by` will still lead to duplicated records.
|
1269
1614
|
|
1270
|
-
*
|
1615
|
+
*Jean Boussier*, *Alex Kitchens*
|
1271
1616
|
|
1272
|
-
|
1617
|
+
* Introduce a simpler constructor API for ActiveRecord database adapters.
|
1273
1618
|
|
1274
|
-
|
1619
|
+
Previously the adapter had to know how to build a new raw connection to
|
1620
|
+
support reconnect, but also expected to be passed an initial already-
|
1621
|
+
established connection.
|
1275
1622
|
|
1276
|
-
|
1623
|
+
When manually creating an adapter instance, it will now accept a single
|
1624
|
+
config hash, and only establish the real connection on demand.
|
1277
1625
|
|
1278
|
-
|
1626
|
+
*Matthew Draper*
|
1279
1627
|
|
1280
|
-
|
1628
|
+
* Avoid redundant `SELECT 1` connection-validation query during DB pool
|
1629
|
+
checkout when possible.
|
1281
1630
|
|
1282
|
-
|
1631
|
+
If the first query run during a request is known to be idempotent, it can be
|
1632
|
+
used directly to validate the connection, saving a network round-trip.
|
1283
1633
|
|
1284
|
-
|
1634
|
+
*Matthew Draper*
|
1285
1635
|
|
1286
|
-
|
1636
|
+
* Automatically reconnect broken database connections when safe, even
|
1637
|
+
mid-request.
|
1287
1638
|
|
1288
|
-
|
1639
|
+
When an error occurs while attempting to run a known-idempotent query, and
|
1640
|
+
not inside a transaction, it is safe to immediately reconnect to the
|
1641
|
+
database server and try again, so this is now the default behavior.
|
1289
1642
|
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
database: my_database
|
1295
|
-
primary_shard_one:
|
1296
|
-
database: my_database_shard_one
|
1297
|
-
```
|
1643
|
+
This new default should always be safe -- to support that, it's consciously
|
1644
|
+
conservative about which queries are considered idempotent -- but if
|
1645
|
+
necessary it can be disabled by setting the `connection_retries` connection
|
1646
|
+
option to `0`.
|
1298
1647
|
|
1299
|
-
|
1648
|
+
*Matthew Draper*
|
1300
1649
|
|
1301
|
-
|
1302
|
-
class ApplicationRecord < ActiveRecord::Base
|
1303
|
-
self.abstract_class = true
|
1650
|
+
* Avoid removing a PostgreSQL extension when there are dependent objects.
|
1304
1651
|
|
1305
|
-
|
1306
|
-
default: { writing: :primary },
|
1307
|
-
shard_one: { writing: :primary_shard_one }
|
1308
|
-
}
|
1309
|
-
```
|
1652
|
+
Previously, removing an extension also implicitly removed dependent objects. Now, this will raise an error.
|
1310
1653
|
|
1311
|
-
|
1654
|
+
You can force removing the extension:
|
1312
1655
|
|
1313
1656
|
```ruby
|
1314
|
-
|
1315
|
-
# Read from shard one
|
1316
|
-
end
|
1657
|
+
disable_extension :citext, force: :cascade
|
1317
1658
|
```
|
1318
1659
|
|
1319
|
-
|
1660
|
+
Fixes #29091.
|
1320
1661
|
|
1321
|
-
*
|
1662
|
+
*fatkodima*
|
1322
1663
|
|
1323
|
-
*
|
1664
|
+
* Allow nested functions as safe SQL string
|
1324
1665
|
|
1325
|
-
|
1666
|
+
*Michael Siegfried*
|
1326
1667
|
|
1327
|
-
|
1668
|
+
* Allow `destroy_association_async_job=` to be configured with a class string instead of a constant.
|
1328
1669
|
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
```
|
1670
|
+
Defers an autoloading dependency between `ActiveRecord::Base` and `ActiveJob::Base`
|
1671
|
+
and moves the configuration of `ActiveRecord::DestroyAssociationAsyncJob`
|
1672
|
+
from ActiveJob to ActiveRecord.
|
1333
1673
|
|
1334
|
-
|
1674
|
+
Deprecates `ActiveRecord::ActiveJobRequiredError` and now raises a `NameError`
|
1675
|
+
if the job class is unloadable or an `ActiveRecord::ConfigurationError` if
|
1676
|
+
`dependent: :destroy_async` is declared on an association but there is no job
|
1677
|
+
class configured.
|
1335
1678
|
|
1336
|
-
|
1337
|
-
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "development", name: "primary")
|
1338
|
-
db_config.name
|
1339
|
-
```
|
1679
|
+
*Ben Sheldon*
|
1340
1680
|
|
1341
|
-
|
1681
|
+
* Fix `ActiveRecord::Store` to serialize as a regular Hash
|
1682
|
+
|
1683
|
+
Previously it would serialize as an `ActiveSupport::HashWithIndifferentAccess`
|
1684
|
+
which is wasteful and cause problem with YAML safe_load.
|
1342
1685
|
|
1343
|
-
*
|
1686
|
+
*Jean Boussier*
|
1344
1687
|
|
1345
|
-
|
1346
|
-
database. For example:
|
1688
|
+
* Add `timestamptz` as a time zone aware type for PostgreSQL
|
1347
1689
|
|
1348
|
-
|
1349
|
-
rails db:create
|
1350
|
-
rails db:create:primary
|
1351
|
-
rails db:create:animals
|
1352
|
-
rails db:drop
|
1353
|
-
rails db:drop:primary
|
1354
|
-
rails db:drop:animals
|
1355
|
-
rails db:migrate
|
1356
|
-
rails db:migrate:primary
|
1357
|
-
rails db:migrate:animals
|
1358
|
-
```
|
1690
|
+
This is required for correctly parsing `timestamp with time zone` values in your database.
|
1359
1691
|
|
1360
|
-
|
1361
|
-
`rails db:test:prepare` can additionally operate on a single database. For example:
|
1692
|
+
If you don't want this, you can opt out by adding this initializer:
|
1362
1693
|
|
1363
|
-
```
|
1364
|
-
|
1365
|
-
rails db:schema:dump:primary
|
1366
|
-
rails db:schema:dump:animals
|
1367
|
-
rails db:schema:load
|
1368
|
-
rails db:schema:load:primary
|
1369
|
-
rails db:schema:load:animals
|
1370
|
-
rails db:structure:dump
|
1371
|
-
rails db:structure:dump:primary
|
1372
|
-
rails db:structure:dump:animals
|
1373
|
-
rails db:structure:load
|
1374
|
-
rails db:structure:load:primary
|
1375
|
-
rails db:structure:load:animals
|
1376
|
-
rails db:test:prepare
|
1377
|
-
rails db:test:prepare:primary
|
1378
|
-
rails db:test:prepare:animals
|
1694
|
+
```ruby
|
1695
|
+
ActiveRecord::Base.time_zone_aware_types -= [:timestamptz]
|
1379
1696
|
```
|
1380
1697
|
|
1381
|
-
*
|
1698
|
+
*Alex Ghiculescu*
|
1382
1699
|
|
1383
|
-
* Add
|
1700
|
+
* Add new `ActiveRecord::Base.generates_token_for` API.
|
1384
1701
|
|
1385
|
-
|
1702
|
+
Currently, `signed_id` fulfills the role of generating tokens for e.g.
|
1703
|
+
resetting a password. However, signed IDs cannot reflect record state, so
|
1704
|
+
if a token is intended to be single-use, it must be tracked in a database at
|
1705
|
+
least until it expires.
|
1386
1706
|
|
1387
|
-
|
1707
|
+
With `generates_token_for`, a token can embed data from a record. When
|
1708
|
+
using the token to fetch the record, the data from the token and the current
|
1709
|
+
data from the record will be compared. If the two do not match, the token
|
1710
|
+
will be treated as invalid, the same as if it had expired. For example:
|
1388
1711
|
|
1389
1712
|
```ruby
|
1390
|
-
class
|
1391
|
-
|
1713
|
+
class User < ActiveRecord::Base
|
1714
|
+
has_secure_password
|
1715
|
+
|
1716
|
+
generates_token_for :password_reset, expires_in: 15.minutes do
|
1717
|
+
# A password's BCrypt salt changes when the password is updated.
|
1718
|
+
# By embedding (part of) the salt in a token, the token will
|
1719
|
+
# expire when the password is updated.
|
1720
|
+
BCrypt::Password.new(password_digest).salt[-10..]
|
1721
|
+
end
|
1392
1722
|
end
|
1393
1723
|
|
1394
|
-
|
1395
|
-
|
1396
|
-
|
1724
|
+
user = User.first
|
1725
|
+
token = user.generate_token_for(:password_reset)
|
1726
|
+
|
1727
|
+
User.find_by_token_for(:password_reset, token) # => user
|
1728
|
+
|
1729
|
+
user.update!(password: "new password")
|
1730
|
+
User.find_by_token_for(:password_reset, token) # => nil
|
1397
1731
|
```
|
1398
1732
|
|
1399
|
-
*
|
1733
|
+
*Jonathan Hefner*
|
1400
1734
|
|
1401
|
-
*
|
1735
|
+
* Optimize Active Record batching for whole table iterations.
|
1402
1736
|
|
1403
|
-
|
1737
|
+
Previously, `in_batches` got all the ids and constructed an `IN`-based query for each batch.
|
1738
|
+
When iterating over the whole tables, this approach is not optimal as it loads unneeded ids and
|
1739
|
+
`IN` queries with lots of items are slow.
|
1404
1740
|
|
1405
|
-
|
1741
|
+
Now, whole table iterations use range iteration (`id >= x AND id <= y`) by default which can make iteration
|
1742
|
+
several times faster. E.g., tested on a PostgreSQL table with 10 million records: querying (`253s` vs `30s`),
|
1743
|
+
updating (`288s` vs `124s`), deleting (`268s` vs `83s`).
|
1744
|
+
|
1745
|
+
Only whole table iterations use this style of iteration by default. You can disable this behavior by passing `use_ranges: false`.
|
1746
|
+
If you iterate over the table and the only condition is, e.g., `archived_at: nil` (and only a tiny fraction
|
1747
|
+
of the records are archived), it makes sense to opt in to this approach:
|
1406
1748
|
|
1407
1749
|
```ruby
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1750
|
+
Project.where(archived_at: nil).in_batches(use_ranges: true) do |relation|
|
1751
|
+
# do something
|
1752
|
+
end
|
1411
1753
|
```
|
1412
1754
|
|
1413
|
-
|
1755
|
+
See #45414 for more details.
|
1414
1756
|
|
1415
|
-
*
|
1757
|
+
*fatkodima*
|
1416
1758
|
|
1417
|
-
|
1759
|
+
* `.with` query method added. Construct common table expressions with ease and get `ActiveRecord::Relation` back.
|
1418
1760
|
|
1419
|
-
|
1761
|
+
```ruby
|
1762
|
+
Post.with(posts_with_comments: Post.where("comments_count > ?", 0))
|
1763
|
+
# => ActiveRecord::Relation
|
1764
|
+
# WITH posts_with_comments AS (SELECT * FROM posts WHERE (comments_count > 0)) SELECT * FROM posts
|
1765
|
+
```
|
1420
1766
|
|
1421
|
-
|
1767
|
+
*Vlado Cingel*
|
1422
1768
|
|
1423
|
-
|
1769
|
+
* Don't establish a new connection if an identical pool exists already.
|
1424
1770
|
|
1425
|
-
|
1426
|
-
class AddColumnTitle < ActiveRecord::Migration[6.1]
|
1427
|
-
def change
|
1428
|
-
add_column :posts, :title, :string, if_not_exists: true
|
1429
|
-
end
|
1430
|
-
end
|
1431
|
-
```
|
1771
|
+
Previously, if `establish_connection` was called on a class that already had an established connection, the existing connection would be removed regardless of whether it was the same config. Now if a pool is found with the same values as the new connection, the existing connection will be returned instead of creating a new one.
|
1432
1772
|
|
1433
|
-
|
1434
|
-
class RemoveColumnTitle < ActiveRecord::Migration[6.1]
|
1435
|
-
def change
|
1436
|
-
remove_column :posts, :title, if_exists: true
|
1437
|
-
end
|
1438
|
-
end
|
1439
|
-
```
|
1773
|
+
This has a slight change in behavior if application code is depending on a new connection being established regardless of whether it's identical to an existing connection. If the old behavior is desirable, applications should call `ActiveRecord::Base#remove_connection` before establishing a new one. Calling `establish_connection` with a different config works the same way as it did previously.
|
1440
1774
|
|
1441
1775
|
*Eileen M. Uchitelle*
|
1442
1776
|
|
1443
|
-
*
|
1777
|
+
* Update `db:prepare` task to load schema when an uninitialized database exists, and dump schema after migrations.
|
1444
1778
|
|
1445
|
-
|
1779
|
+
*Ben Sheldon*
|
1446
1780
|
|
1447
|
-
|
1781
|
+
* Fix supporting timezone awareness for `tsrange` and `tstzrange` array columns.
|
1448
1782
|
|
1449
|
-
|
1783
|
+
```ruby
|
1784
|
+
# In database migrations
|
1785
|
+
add_column :shops, :open_hours, :tsrange, array: true
|
1786
|
+
# In app config
|
1787
|
+
ActiveRecord::Base.time_zone_aware_types += [:tsrange]
|
1788
|
+
# In the code times are properly converted to app time zone
|
1789
|
+
Shop.create!(open_hours: [Time.current..8.hour.from_now])
|
1790
|
+
```
|
1450
1791
|
|
1451
|
-
|
1792
|
+
*Wojciech Wnętrzak*
|
1452
1793
|
|
1453
|
-
|
1794
|
+
* Introduce strategy pattern for executing migrations.
|
1454
1795
|
|
1455
|
-
|
1796
|
+
By default, migrations will use a strategy object that delegates the method
|
1797
|
+
to the connection adapter. Consumers can implement custom strategy objects
|
1798
|
+
to change how their migrations run.
|
1456
1799
|
|
1457
|
-
*
|
1800
|
+
*Adrianna Chang*
|
1458
1801
|
|
1459
|
-
|
1802
|
+
* Add adapter option disallowing foreign keys
|
1803
|
+
|
1804
|
+
This adds a new option to be added to `database.yml` which enables skipping
|
1805
|
+
foreign key constraints usage even if the underlying database supports them.
|
1460
1806
|
|
1807
|
+
Usage:
|
1461
1808
|
```yaml
|
1462
1809
|
development:
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
schema_cache_path: tmp/schema/main.yml
|
1810
|
+
<<: *default
|
1811
|
+
database: storage/development.sqlite3
|
1812
|
+
foreign_keys: false
|
1467
1813
|
```
|
1468
1814
|
|
1469
|
-
*
|
1815
|
+
*Paulo Barros*
|
1470
1816
|
|
1471
|
-
*
|
1817
|
+
* Add configurable deprecation warning for singular associations
|
1472
1818
|
|
1473
|
-
|
1819
|
+
This adds a deprecation warning when using the plural name of a singular associations in `where`.
|
1820
|
+
It is possible to opt into the new more performant behavior with `config.active_record.allow_deprecated_singular_associations_name = false`
|
1474
1821
|
|
1475
|
-
*
|
1822
|
+
*Adam Hess*
|
1476
1823
|
|
1477
|
-
*
|
1824
|
+
* Run transactional callbacks on the freshest instance to save a given
|
1825
|
+
record within a transaction.
|
1478
1826
|
|
1479
|
-
|
1827
|
+
When multiple Active Record instances change the same record within a
|
1828
|
+
transaction, Rails runs `after_commit` or `after_rollback` callbacks for
|
1829
|
+
only one of them. `config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction`
|
1830
|
+
was added to specify how Rails chooses which instance receives the
|
1831
|
+
callbacks. The framework defaults were changed to use the new logic.
|
1480
1832
|
|
1481
|
-
|
1833
|
+
When `config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction`
|
1834
|
+
is `true`, transactional callbacks are run on the first instance to save,
|
1835
|
+
even though its instance state may be stale.
|
1482
1836
|
|
1483
|
-
|
1837
|
+
When it is `false`, which is the new framework default starting with version
|
1838
|
+
7.1, transactional callbacks are run on the instances with the freshest
|
1839
|
+
instance state. Those instances are chosen as follows:
|
1484
1840
|
|
1485
|
-
|
1841
|
+
- In general, run transactional callbacks on the last instance to save a
|
1842
|
+
given record within the transaction.
|
1843
|
+
- There are two exceptions:
|
1844
|
+
- If the record is created within the transaction, then updated by
|
1845
|
+
another instance, `after_create_commit` callbacks will be run on the
|
1846
|
+
second instance. This is instead of the `after_update_commit`
|
1847
|
+
callbacks that would naively be run based on that instance’s state.
|
1848
|
+
- If the record is destroyed within the transaction, then
|
1849
|
+
`after_destroy_commit` callbacks will be fired on the last destroyed
|
1850
|
+
instance, even if a stale instance subsequently performed an update
|
1851
|
+
(which will have affected 0 rows).
|
1486
1852
|
|
1487
|
-
*
|
1853
|
+
*Cameron Bothner and Mitch Vollebregt*
|
1488
1854
|
|
1489
|
-
|
1855
|
+
* Enable strict strings mode for `SQLite3Adapter`.
|
1856
|
+
|
1857
|
+
Configures SQLite with a strict strings mode, which disables double-quoted string literals.
|
1858
|
+
|
1859
|
+
SQLite has some quirks around double-quoted string literals.
|
1860
|
+
It first tries to consider double-quoted strings as identifier names, but if they don't exist
|
1861
|
+
it then considers them as string literals. Because of this, typos can silently go unnoticed.
|
1862
|
+
For example, it is possible to create an index for a non existing column.
|
1863
|
+
See [SQLite documentation](https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted) for more details.
|
1864
|
+
|
1865
|
+
If you don't want this behavior, you can disable it via:
|
1490
1866
|
|
1491
1867
|
```ruby
|
1492
|
-
|
1868
|
+
# config/application.rb
|
1869
|
+
config.active_record.sqlite3_adapter_strict_strings_by_default = false
|
1493
1870
|
```
|
1494
1871
|
|
1495
|
-
|
1872
|
+
Fixes #27782.
|
1873
|
+
|
1874
|
+
*fatkodima*, *Jean Boussier*
|
1875
|
+
|
1876
|
+
* Resolve issue where a relation cache_version could be left stale.
|
1877
|
+
|
1878
|
+
Previously, when `reset` was called on a relation object it did not reset the cache_versions
|
1879
|
+
ivar. This led to a confusing situation where despite having the correct data the relation
|
1880
|
+
still reported a stale cache_version.
|
1881
|
+
|
1882
|
+
Usage:
|
1496
1883
|
|
1497
1884
|
```ruby
|
1498
|
-
|
1885
|
+
developers = Developer.all
|
1886
|
+
developers.cache_version
|
1887
|
+
|
1888
|
+
Developer.update_all(updated_at: Time.now.utc + 1.second)
|
1889
|
+
|
1890
|
+
developers.cache_version # Stale cache_version
|
1891
|
+
developers.reset
|
1892
|
+
developers.cache_version # Returns the current correct cache_version
|
1499
1893
|
```
|
1500
1894
|
|
1501
|
-
|
1895
|
+
Fixes #45341.
|
1502
1896
|
|
1503
|
-
*
|
1897
|
+
*Austen Madden*
|
1504
1898
|
|
1505
|
-
|
1899
|
+
* Add support for exclusion constraints (PostgreSQL-only).
|
1506
1900
|
|
1507
|
-
|
1901
|
+
```ruby
|
1902
|
+
add_exclusion_constraint :invoices, "daterange(start_date, end_date) WITH &&", using: :gist, name: "invoices_date_overlap"
|
1903
|
+
remove_exclusion_constraint :invoices, name: "invoices_date_overlap"
|
1904
|
+
```
|
1508
1905
|
|
1509
|
-
|
1906
|
+
See PostgreSQL's [`CREATE TABLE ... EXCLUDE ...`](https://www.postgresql.org/docs/12/sql-createtable.html#SQL-CREATETABLE-EXCLUDE) documentation for more on exclusion constraints.
|
1510
1907
|
|
1511
|
-
|
1908
|
+
*Alex Robbin*
|
1512
1909
|
|
1513
|
-
|
1910
|
+
* `change_column_null` raises if a non-boolean argument is provided
|
1514
1911
|
|
1515
|
-
|
1516
|
-
|
1912
|
+
Previously if you provided a non-boolean argument, `change_column_null` would
|
1913
|
+
treat it as truthy and make your column nullable. This could be surprising, so now
|
1914
|
+
the input must be either `true` or `false`.
|
1517
1915
|
|
1518
|
-
|
1916
|
+
```ruby
|
1917
|
+
change_column_null :table, :column, true # good
|
1918
|
+
change_column_null :table, :column, false # good
|
1919
|
+
change_column_null :table, :column, from: true, to: false # raises (previously this made the column nullable)
|
1920
|
+
```
|
1921
|
+
|
1922
|
+
*Alex Ghiculescu*
|
1519
1923
|
|
1520
|
-
* Enforce
|
1521
|
-
ActiveRecord::Relation#cache_key_with_version. This method will be used by
|
1522
|
-
ActionController::ConditionalGet to ensure that when collection cache versioning
|
1523
|
-
is enabled, requests using ConditionalGet don't return the same ETag header
|
1524
|
-
after a collection is modified.
|
1924
|
+
* Enforce limit on table names length.
|
1525
1925
|
|
1526
|
-
Fixes #
|
1926
|
+
Fixes #45130.
|
1527
1927
|
|
1528
|
-
*
|
1928
|
+
*fatkodima*
|
1529
1929
|
|
1530
|
-
*
|
1531
|
-
with `DATABASE_URL` set.
|
1930
|
+
* Adjust the minimum MariaDB version for check constraints support.
|
1532
1931
|
|
1533
|
-
*
|
1932
|
+
*Eddie Lebow*
|
1534
1933
|
|
1535
|
-
*
|
1934
|
+
* Fix Hstore deserialize regression.
|
1536
1935
|
|
1537
|
-
|
1936
|
+
*edsharp*
|
1538
1937
|
|
1539
|
-
|
1938
|
+
* Add validity for PostgreSQL indexes.
|
1540
1939
|
|
1541
1940
|
```ruby
|
1542
|
-
|
1543
|
-
|
1941
|
+
connection.index_exists?(:users, :email, valid: true)
|
1942
|
+
connection.indexes(:users).select(&:valid?)
|
1544
1943
|
```
|
1545
1944
|
|
1546
|
-
|
1945
|
+
*fatkodima*
|
1946
|
+
|
1947
|
+
* Fix eager loading for models without primary keys.
|
1948
|
+
|
1949
|
+
*Anmol Chopra*, *Matt Lawrence*, and *Jonathan Hefner*
|
1950
|
+
|
1951
|
+
* Avoid validating a unique field if it has not changed and is backed by a unique index.
|
1952
|
+
|
1953
|
+
Previously, when saving a record, Active Record will perform an extra query to check for the
|
1954
|
+
uniqueness of each attribute having a `uniqueness` validation, even if that attribute hasn't changed.
|
1955
|
+
If the database has the corresponding unique index, then this validation can never fail for persisted
|
1956
|
+
records, and we could safely skip it.
|
1957
|
+
|
1958
|
+
*fatkodima*
|
1959
|
+
|
1960
|
+
* Stop setting `sql_auto_is_null`
|
1961
|
+
|
1962
|
+
Since version 5.5 the default has been off, we no longer have to manually turn it off.
|
1963
|
+
|
1964
|
+
*Adam Hess*
|
1965
|
+
|
1966
|
+
* Fix `touch` to raise an error for readonly columns.
|
1967
|
+
|
1968
|
+
*fatkodima*
|
1969
|
+
|
1970
|
+
* Add ability to ignore tables by regexp for SQL schema dumps.
|
1547
1971
|
|
1548
1972
|
```ruby
|
1549
|
-
|
1550
|
-
config = @db_config.configuration_hash.merge(idle_timeout: "0.02")
|
1551
|
-
db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(@db_config.env_name, @db_config.spec_name, config)
|
1973
|
+
ActiveRecord::SchemaDumper.ignore_tables = [/^_/]
|
1552
1974
|
```
|
1553
1975
|
|
1554
|
-
*
|
1555
|
-
|
1556
|
-
* Remove `:connection_id` from the `sql.active_record` notification.
|
1976
|
+
*fatkodima*
|
1557
1977
|
|
1558
|
-
|
1978
|
+
* Avoid queries when performing calculations on contradictory relations.
|
1559
1979
|
|
1560
|
-
|
1980
|
+
Previously calculations would make a query even when passed a
|
1981
|
+
contradiction, such as `User.where(id: []).count`. We no longer perform a
|
1982
|
+
query in that scenario.
|
1561
1983
|
|
1562
|
-
|
1984
|
+
This applies to the following calculations: `count`, `sum`, `average`,
|
1985
|
+
`minimum` and `maximum`
|
1563
1986
|
|
1564
|
-
*
|
1987
|
+
*Luan Vieira, John Hawthorn and Daniel Colson*
|
1565
1988
|
|
1566
|
-
|
1567
|
-
by default.
|
1989
|
+
* Allow using aliased attributes with `insert_all`/`upsert_all`.
|
1568
1990
|
|
1569
|
-
|
1570
|
-
|
1991
|
+
```ruby
|
1992
|
+
class Book < ApplicationRecord
|
1993
|
+
alias_attribute :title, :name
|
1994
|
+
end
|
1571
1995
|
|
1572
|
-
|
1996
|
+
Book.insert_all [{ title: "Remote", author_id: 1 }], returning: :title
|
1997
|
+
```
|
1573
1998
|
|
1574
|
-
*
|
1999
|
+
*fatkodima*
|
1575
2000
|
|
1576
|
-
|
2001
|
+
* Support encrypted attributes on columns with default db values.
|
1577
2002
|
|
1578
|
-
|
2003
|
+
This adds support for encrypted attributes defined on columns with default values.
|
2004
|
+
It will encrypt those values at creation time. Before, it would raise an
|
2005
|
+
error unless `config.active_record.encryption.support_unencrypted_data` was true.
|
1579
2006
|
|
1580
|
-
|
2007
|
+
*Jorge Manrubia* and *Dima Fatko*
|
1581
2008
|
|
1582
|
-
|
2009
|
+
* Allow overriding `reading_request?` in `DatabaseSelector::Resolver`
|
1583
2010
|
|
1584
|
-
|
2011
|
+
The default implementation checks if a request is a `get?` or `head?`,
|
2012
|
+
but you can now change it to anything you like. If the method returns true,
|
2013
|
+
`Resolver#read` gets called meaning the request could be served by the
|
2014
|
+
replica database.
|
1585
2015
|
|
1586
|
-
*
|
2016
|
+
*Alex Ghiculescu*
|
1587
2017
|
|
1588
|
-
*
|
2018
|
+
* Remove `ActiveRecord.legacy_connection_handling`.
|
1589
2019
|
|
1590
|
-
*
|
2020
|
+
*Eileen M. Uchitelle*
|
1591
2021
|
|
1592
|
-
*
|
2022
|
+
* `rails db:schema:{dump,load}` now checks `ENV["SCHEMA_FORMAT"]` before config
|
1593
2023
|
|
1594
|
-
|
2024
|
+
Since `rails db:structure:{dump,load}` was deprecated there wasn't a simple
|
2025
|
+
way to dump a schema to both SQL and Ruby formats. You can now do this with
|
2026
|
+
an environment variable. For example:
|
1595
2027
|
|
1596
|
-
|
2028
|
+
```
|
2029
|
+
SCHEMA_FORMAT=sql rake db:schema:dump
|
2030
|
+
```
|
1597
2031
|
|
1598
|
-
*
|
2032
|
+
*Alex Ghiculescu*
|
1599
2033
|
|
1600
|
-
*
|
2034
|
+
* Fixed MariaDB default function support.
|
1601
2035
|
|
1602
|
-
|
2036
|
+
Defaults would be written wrong in "db/schema.rb" and not work correctly
|
2037
|
+
if using `db:schema:load`. Further more the function name would be
|
2038
|
+
added as string content when saving new records.
|
1603
2039
|
|
1604
|
-
*
|
2040
|
+
*kaspernj*
|
1605
2041
|
|
1606
|
-
|
2042
|
+
* Add `active_record.destroy_association_async_batch_size` configuration
|
1607
2043
|
|
1608
|
-
|
2044
|
+
This allows applications to specify the maximum number of records that will
|
2045
|
+
be destroyed in a single background job by the `dependent: :destroy_async`
|
2046
|
+
association option. By default, the current behavior will remain the same:
|
2047
|
+
when a parent record is destroyed, all dependent records will be destroyed
|
2048
|
+
in a single background job. If the number of dependent records is greater
|
2049
|
+
than this configuration, the records will be destroyed in multiple
|
2050
|
+
background jobs.
|
1609
2051
|
|
1610
|
-
*
|
2052
|
+
*Nick Holden*
|
1611
2053
|
|
1612
|
-
*
|
2054
|
+
* Fix `remove_foreign_key` with `:if_exists` option when foreign key actually exists.
|
1613
2055
|
|
1614
|
-
*
|
2056
|
+
*fatkodima*
|
1615
2057
|
|
1616
|
-
*
|
1617
|
-
is set at 24 characters.
|
2058
|
+
* Remove `--no-comments` flag in structure dumps for PostgreSQL
|
1618
2059
|
|
1619
|
-
|
2060
|
+
This broke some apps that used custom schema comments. If you don't want
|
2061
|
+
comments in your structure dump, you can use:
|
1620
2062
|
|
1621
2063
|
```ruby
|
1622
|
-
|
2064
|
+
ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = ['--no-comments']
|
1623
2065
|
```
|
1624
2066
|
|
1625
|
-
|
2067
|
+
*Alex Ghiculescu*
|
1626
2068
|
|
1627
|
-
|
1628
|
-
has_secure_token :default_token # 24 characters
|
1629
|
-
has_secure_token :auth_token, length: 36 # 36 characters
|
1630
|
-
has_secure_token :invalid_token, length: 12 # => ActiveRecord::SecureToken::MinimumLengthError
|
1631
|
-
```
|
2069
|
+
* Reduce the memory footprint of fixtures accessors.
|
1632
2070
|
|
1633
|
-
|
2071
|
+
Until now fixtures accessors were eagerly defined using `define_method`.
|
2072
|
+
So the memory usage was directly dependent of the number of fixtures and
|
2073
|
+
test suites.
|
1634
2074
|
|
1635
|
-
|
2075
|
+
Instead fixtures accessors are now implemented with `method_missing`,
|
2076
|
+
so they incur much less memory and CPU overhead.
|
1636
2077
|
|
1637
|
-
*
|
2078
|
+
*Jean Boussier*
|
1638
2079
|
|
1639
|
-
*
|
2080
|
+
* Fix `config.active_record.destroy_association_async_job` configuration
|
1640
2081
|
|
1641
|
-
|
2082
|
+
`config.active_record.destroy_association_async_job` should allow
|
2083
|
+
applications to specify the job that will be used to destroy associated
|
2084
|
+
records in the background for `has_many` associations with the
|
2085
|
+
`dependent: :destroy_async` option. Previously, that was ignored, which
|
2086
|
+
meant the default `ActiveRecord::DestroyAssociationAsyncJob` always
|
2087
|
+
destroyed records in the background.
|
1642
2088
|
|
1643
|
-
*
|
2089
|
+
*Nick Holden*
|
1644
2090
|
|
1645
|
-
|
2091
|
+
* Fix `change_column_comment` to preserve column's AUTO_INCREMENT in the MySQL adapter
|
1646
2092
|
|
1647
|
-
|
2093
|
+
*fatkodima*
|
1648
2094
|
|
1649
|
-
|
1650
|
-
add_index :reports, :report_id, unique: true # => works
|
1651
|
-
remove_index :reports, :report_id # => works
|
1652
|
-
remove_index :reports, :report_id, unique: true # => ArgumentError
|
2095
|
+
* Fix quoting of `ActiveSupport::Duration` and `Rational` numbers in the MySQL adapter.
|
1653
2096
|
|
1654
|
-
|
2097
|
+
*Kevin McPhillips*
|
1655
2098
|
|
1656
|
-
|
2099
|
+
* Allow column name with COLLATE (e.g., title COLLATE "C") as safe SQL string
|
1657
2100
|
|
1658
|
-
*
|
2101
|
+
*Shugo Maeda*
|
1659
2102
|
|
1660
|
-
*
|
2103
|
+
* Permit underscores in the VERSION argument to database rake tasks.
|
1661
2104
|
|
1662
|
-
*
|
2105
|
+
*Eddie Lebow*
|
1663
2106
|
|
1664
|
-
*
|
2107
|
+
* Reversed the order of `INSERT` statements in `structure.sql` dumps
|
1665
2108
|
|
1666
|
-
|
2109
|
+
This should decrease the likelihood of merge conflicts. New migrations
|
2110
|
+
will now be added at the top of the list.
|
1667
2111
|
|
1668
|
-
|
2112
|
+
For existing apps, there will be a large diff the next time `structure.sql`
|
2113
|
+
is generated.
|
1669
2114
|
|
1670
|
-
|
2115
|
+
*Alex Ghiculescu*, *Matt Larraz*
|
1671
2116
|
|
1672
|
-
|
2117
|
+
* Fix PG.connect keyword arguments deprecation warning on ruby 2.7
|
1673
2118
|
|
1674
|
-
|
2119
|
+
Fixes #44307.
|
2120
|
+
|
2121
|
+
*Nikita Vasilevsky*
|
1675
2122
|
|
1676
|
-
*
|
2123
|
+
* Fix dropping DB connections after serialization failures and deadlocks.
|
1677
2124
|
|
1678
|
-
|
2125
|
+
Prior to 6.1.4, serialization failures and deadlocks caused rollbacks to be
|
2126
|
+
issued for both real transactions and savepoints. This breaks MySQL which
|
2127
|
+
disallows rollbacks of savepoints following a deadlock.
|
1679
2128
|
|
1680
|
-
|
2129
|
+
6.1.4 removed these rollbacks, for both transactions and savepoints, causing
|
2130
|
+
the DB connection to be left in an unknown state and thus discarded.
|
1681
2131
|
|
1682
|
-
|
2132
|
+
These rollbacks are now restored, except for savepoints on MySQL.
|
1683
2133
|
|
1684
|
-
*
|
2134
|
+
*Thomas Morgan*
|
1685
2135
|
|
1686
|
-
|
2136
|
+
* Make `ActiveRecord::ConnectionPool` Fiber-safe
|
1687
2137
|
|
1688
|
-
|
2138
|
+
When `ActiveSupport::IsolatedExecutionState.isolation_level` is set to `:fiber`,
|
2139
|
+
the connection pool now supports multiple Fibers from the same Thread checking
|
2140
|
+
out connections from the pool.
|
1689
2141
|
|
1690
|
-
*
|
2142
|
+
*Alex Matchneer*
|
1691
2143
|
|
1692
|
-
|
2144
|
+
* Add `update_attribute!` to `ActiveRecord::Persistence`
|
1693
2145
|
|
1694
|
-
|
2146
|
+
Similar to `update_attribute`, but raises `ActiveRecord::RecordNotSaved` when a `before_*` callback throws `:abort`.
|
1695
2147
|
|
1696
|
-
|
2148
|
+
```ruby
|
2149
|
+
class Topic < ActiveRecord::Base
|
2150
|
+
before_save :check_title
|
1697
2151
|
|
1698
|
-
|
2152
|
+
def check_title
|
2153
|
+
throw(:abort) if title == "abort"
|
2154
|
+
end
|
2155
|
+
end
|
1699
2156
|
|
1700
|
-
|
2157
|
+
topic = Topic.create(title: "Test Title")
|
2158
|
+
# #=> #<Topic title: "Test Title">
|
2159
|
+
topic.update_attribute!(:title, "Another Title")
|
2160
|
+
# #=> #<Topic title: "Another Title">
|
2161
|
+
topic.update_attribute!(:title, "abort")
|
2162
|
+
# raises ActiveRecord::RecordNotSaved
|
2163
|
+
```
|
1701
2164
|
|
1702
|
-
*
|
2165
|
+
*Drew Tempelmeyer*
|
1703
2166
|
|
1704
|
-
*
|
2167
|
+
* Avoid loading every record in `ActiveRecord::Relation#pretty_print`
|
1705
2168
|
|
1706
|
-
|
2169
|
+
```ruby
|
2170
|
+
# Before
|
2171
|
+
pp Foo.all # Loads the whole table.
|
1707
2172
|
|
1708
|
-
|
2173
|
+
# After
|
2174
|
+
pp Foo.all # Shows 10 items and an ellipsis.
|
2175
|
+
```
|
1709
2176
|
|
1710
|
-
|
1711
|
-
enum status: [:sent, :not_sent]
|
1712
|
-
end
|
2177
|
+
*Ulysse Buonomo*
|
1713
2178
|
|
1714
|
-
|
2179
|
+
* Change `QueryMethods#in_order_of` to drop records not listed in values.
|
1715
2180
|
|
1716
|
-
|
2181
|
+
`in_order_of` now filters down to the values provided, to match the behavior of the `Enumerable` version.
|
1717
2182
|
|
1718
|
-
*
|
2183
|
+
*Kevin Newton*
|
1719
2184
|
|
1720
|
-
*
|
2185
|
+
* Allow named expression indexes to be revertible.
|
1721
2186
|
|
1722
|
-
|
2187
|
+
Previously, the following code would raise an error in a reversible migration executed while rolling back, due to the index name not being used in the index removal.
|
1723
2188
|
|
1724
|
-
|
2189
|
+
```ruby
|
2190
|
+
add_index(:settings, "(data->'property')", using: :gin, name: :index_settings_data_property)
|
2191
|
+
```
|
1725
2192
|
|
1726
|
-
|
2193
|
+
Fixes #43331.
|
1727
2194
|
|
1728
|
-
*
|
2195
|
+
*Oliver Günther*
|
1729
2196
|
|
1730
|
-
|
2197
|
+
* Fix incorrect argument in PostgreSQL structure dump tasks.
|
1731
2198
|
|
1732
|
-
|
2199
|
+
Updating the `--no-comment` argument added in Rails 7 to the correct `--no-comments` argument.
|
1733
2200
|
|
1734
|
-
|
2201
|
+
*Alex Dent*
|
1735
2202
|
|
1736
|
-
|
2203
|
+
* Fix migration compatibility to create SQLite references/belongs_to column as integer when migration version is 6.0.
|
1737
2204
|
|
1738
|
-
|
2205
|
+
Reference/belongs_to in migrations with version 6.0 were creating columns as
|
2206
|
+
bigint instead of integer for the SQLite Adapter.
|
2207
|
+
|
2208
|
+
*Marcelo Lauxen*
|
2209
|
+
|
2210
|
+
* Fix `QueryMethods#in_order_of` to handle empty order list.
|
1739
2211
|
|
1740
|
-
|
2212
|
+
```ruby
|
2213
|
+
Post.in_order_of(:id, []).to_a
|
2214
|
+
```
|
1741
2215
|
|
1742
|
-
|
2216
|
+
Also more explicitly set the column as secondary order, so that any other
|
2217
|
+
value is still ordered.
|
2218
|
+
|
2219
|
+
*Jean Boussier*
|
1743
2220
|
|
1744
|
-
*
|
2221
|
+
* Fix quoting of column aliases generated by calculation methods.
|
1745
2222
|
|
1746
|
-
|
2223
|
+
Since the alias is derived from the table name, we can't assume the result
|
2224
|
+
is a valid identifier.
|
1747
2225
|
|
1748
|
-
|
2226
|
+
```ruby
|
2227
|
+
class Test < ActiveRecord::Base
|
2228
|
+
self.table_name = '1abc'
|
2229
|
+
end
|
2230
|
+
Test.group(:id).count
|
2231
|
+
# syntax error at or near "1" (ActiveRecord::StatementInvalid)
|
2232
|
+
# LINE 1: SELECT COUNT(*) AS count_all, "1abc"."id" AS 1abc_id FROM "1...
|
2233
|
+
```
|
1749
2234
|
|
1750
|
-
*
|
2235
|
+
*Jean Boussier*
|
1751
2236
|
|
1752
|
-
*
|
2237
|
+
* Add `authenticate_by` when using `has_secure_password`.
|
1753
2238
|
|
1754
|
-
|
2239
|
+
`authenticate_by` is intended to replace code like the following, which
|
2240
|
+
returns early when a user with a matching email is not found:
|
1755
2241
|
|
1756
|
-
|
2242
|
+
```ruby
|
2243
|
+
User.find_by(email: "...")&.authenticate("...")
|
2244
|
+
```
|
1757
2245
|
|
1758
|
-
|
2246
|
+
Such code is vulnerable to timing-based enumeration attacks, wherein an
|
2247
|
+
attacker can determine if a user account with a given email exists. After
|
2248
|
+
confirming that an account exists, the attacker can try passwords associated
|
2249
|
+
with that email address from other leaked databases, in case the user
|
2250
|
+
re-used a password across multiple sites (a common practice). Additionally,
|
2251
|
+
knowing an account email address allows the attacker to attempt a targeted
|
2252
|
+
phishing ("spear phishing") attack.
|
1759
2253
|
|
1760
|
-
|
2254
|
+
`authenticate_by` addresses the vulnerability by taking the same amount of
|
2255
|
+
time regardless of whether a user with a matching email is found:
|
1761
2256
|
|
1762
|
-
|
2257
|
+
```ruby
|
2258
|
+
User.authenticate_by(email: "...", password: "...")
|
2259
|
+
```
|
1763
2260
|
|
1764
|
-
*
|
2261
|
+
*Jonathan Hefner*
|
1765
2262
|
|
1766
2263
|
|
1767
|
-
Please check [
|
2264
|
+
Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/activerecord/CHANGELOG.md) for previous changes.
|