activerecord 7.0.8.7 → 7.2.3
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 +781 -1777
- data/MIT-LICENSE +1 -1
- data/README.rdoc +30 -30
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +2 -2
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +35 -12
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +40 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +22 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +35 -21
- data/lib/active_record/associations/collection_proxy.rb +29 -11
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +21 -14
- data/lib/active_record/associations/has_many_through_association.rb +17 -7
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -3
- data/lib/active_record/associations/join_dependency.rb +10 -10
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +33 -8
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +354 -485
- data/lib/active_record/attribute_assignment.rb +0 -4
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +53 -35
- data/lib/active_record/attribute_methods/primary_key.rb +45 -25
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +8 -7
- data/lib/active_record/attribute_methods/serialization.rb +131 -32
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -6
- data/lib/active_record/attribute_methods/write.rb +6 -6
- data/lib/active_record/attribute_methods.rb +153 -33
- data/lib/active_record/attributes.rb +96 -71
- data/lib/active_record/autosave_association.rb +81 -39
- data/lib/active_record/base.rb +11 -7
- data/lib/active_record/callbacks.rb +11 -25
- 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 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +123 -131
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +343 -91
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +229 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -63
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +142 -12
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -129
- data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
- data/lib/active_record/connection_adapters/abstract_adapter.rb +539 -111
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +289 -128
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +26 -139
- data/lib/active_record/connection_adapters/mysql/quoting.rb +60 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +25 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +108 -68
- data/lib/active_record/connection_adapters/pool_config.rb +20 -10
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +100 -43
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +65 -61
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +371 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +374 -203
- data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -45
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +14 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +51 -8
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +298 -113
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +124 -1
- data/lib/active_record/connection_handling.rb +101 -105
- data/lib/active_record/core.rb +273 -178
- data/lib/active_record/counter_cache.rb +69 -35
- data/lib/active_record/database_configurations/connection_url_resolver.rb +10 -3
- data/lib/active_record/database_configurations/database_config.rb +26 -5
- data/lib/active_record/database_configurations/hash_config.rb +52 -34
- data/lib/active_record/database_configurations/url_config.rb +37 -12
- data/lib/active_record/database_configurations.rb +87 -34
- data/lib/active_record/delegated_type.rb +56 -27
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +3 -1
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +46 -22
- data/lib/active_record/encryption/encrypted_attribute_type.rb +48 -13
- data/lib/active_record/encryption/encryptor.rb +35 -19
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +6 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +22 -21
- data/lib/active_record/encryption.rb +3 -0
- data/lib/active_record/enum.rb +130 -28
- data/lib/active_record/errors.rb +154 -34
- data/lib/active_record/explain.rb +21 -12
- 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 +48 -10
- data/lib/active_record/fixtures.rb +167 -97
- data/lib/active_record/future_result.rb +47 -8
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +34 -18
- data/lib/active_record/insert_all.rb +72 -22
- data/lib/active_record/integration.rb +11 -8
- data/lib/active_record/internal_metadata.rb +124 -20
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +18 -22
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +6 -8
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +106 -8
- data/lib/active_record/migration/compatibility.rb +147 -5
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +236 -118
- data/lib/active_record/model_schema.rb +90 -102
- data/lib/active_record/nested_attributes.rb +48 -11
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +168 -339
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +18 -25
- data/lib/active_record/query_logs.rb +96 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +35 -10
- data/lib/active_record/railtie.rb +131 -87
- data/lib/active_record/railties/controller_runtime.rb +22 -7
- data/lib/active_record/railties/databases.rake +147 -155
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +267 -69
- data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +270 -108
- data/lib/active_record/relation/delegation.rb +30 -19
- data/lib/active_record/relation/finder_methods.rb +97 -21
- data/lib/active_record/relation/merger.rb +6 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +28 -16
- data/lib/active_record/relation/query_attribute.rb +3 -2
- data/lib/active_record/relation/query_methods.rb +585 -109
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +5 -4
- data/lib/active_record/relation/where_clause.rb +15 -21
- data/lib/active_record/relation.rb +592 -92
- data/lib/active_record/result.rb +49 -48
- data/lib/active_record/runtime_registry.rb +63 -1
- data/lib/active_record/sanitization.rb +70 -25
- data/lib/active_record/schema.rb +8 -7
- data/lib/active_record/schema_dumper.rb +90 -23
- data/lib/active_record/schema_migration.rb +75 -24
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +33 -11
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +1 -1
- data/lib/active_record/tasks/database_tasks.rb +190 -118
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +23 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_fixtures.rb +170 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +31 -17
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +108 -24
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +9 -3
- 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 +61 -11
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +247 -33
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +3 -1
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +6 -2
- data/lib/arel/predications.rb +3 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/table.rb +9 -5
- data/lib/arel/tree_manager.rb +8 -3
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -0
- data/lib/arel/visitors/mysql.rb +17 -5
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +114 -34
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +21 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -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
- metadata +56 -17
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
|
@@ -6,12 +6,13 @@ module ActiveRecord
|
|
|
6
6
|
# See ActiveRecord::Attributes::ClassMethods for documentation
|
|
7
7
|
module Attributes
|
|
8
8
|
extend ActiveSupport::Concern
|
|
9
|
+
include ActiveModel::AttributeRegistration
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
|
|
12
|
-
end
|
|
13
|
-
|
|
11
|
+
# = Active Record \Attributes
|
|
14
12
|
module ClassMethods
|
|
13
|
+
# :method: attribute
|
|
14
|
+
# :call-seq: attribute(name, cast_type = nil, **options)
|
|
15
|
+
#
|
|
15
16
|
# Defines an attribute with a type on this model. It will override the
|
|
16
17
|
# type of existing attributes if needed. This allows control over how
|
|
17
18
|
# values are converted to and from SQL when assigned to a model. It also
|
|
@@ -20,26 +21,34 @@ module ActiveRecord
|
|
|
20
21
|
# your domain objects across much of Active Record, without having to
|
|
21
22
|
# rely on implementation details or monkey patching.
|
|
22
23
|
#
|
|
23
|
-
#
|
|
24
|
-
# column which this will persist to.
|
|
24
|
+
# ==== Parameters
|
|
25
25
|
#
|
|
26
|
-
# +
|
|
27
|
-
#
|
|
28
|
-
#
|
|
26
|
+
# [+name+]
|
|
27
|
+
# The name of the methods to define attribute methods for, and the
|
|
28
|
+
# column which this will persist to.
|
|
29
29
|
#
|
|
30
|
-
#
|
|
30
|
+
# [+cast_type+]
|
|
31
|
+
# A symbol such as +:string+ or +:integer+, or a type object to be used
|
|
32
|
+
# for this attribute. If this parameter is not passed, the previously
|
|
33
|
+
# defined type (if any) will be used. Otherwise, the type will be
|
|
34
|
+
# ActiveModel::Type::Value. See the examples below for more information
|
|
35
|
+
# about providing custom type objects.
|
|
31
36
|
#
|
|
32
|
-
#
|
|
37
|
+
# ==== Options
|
|
33
38
|
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
39
|
+
# [+:default+]
|
|
40
|
+
# The default value to use when no value is provided. If this option is
|
|
41
|
+
# not passed, the previously defined default value (if any) on the
|
|
42
|
+
# superclass or in the schema will be used. Otherwise, the default will
|
|
43
|
+
# be +nil+.
|
|
37
44
|
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
45
|
+
# [+:array+]
|
|
46
|
+
# (PostgreSQL only) Specifies that the type should be an array. See the
|
|
47
|
+
# examples below.
|
|
40
48
|
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
49
|
+
# [+:range+]
|
|
50
|
+
# (PostgreSQL only) Specifies that the type should be a range. See the
|
|
51
|
+
# examples below.
|
|
43
52
|
#
|
|
44
53
|
# When using a symbol for +cast_type+, extra options are forwarded to the
|
|
45
54
|
# constructor of the type object.
|
|
@@ -134,7 +143,7 @@ module ActiveRecord
|
|
|
134
143
|
# expected API. It is recommended that your type objects inherit from an
|
|
135
144
|
# existing type, or from ActiveRecord::Type::Value
|
|
136
145
|
#
|
|
137
|
-
# class
|
|
146
|
+
# class PriceType < ActiveRecord::Type::Integer
|
|
138
147
|
# def cast(value)
|
|
139
148
|
# if !value.kind_of?(Numeric) && value.include?('$')
|
|
140
149
|
# price_in_dollars = value.gsub(/\$/, '').to_f
|
|
@@ -146,11 +155,11 @@ module ActiveRecord
|
|
|
146
155
|
# end
|
|
147
156
|
#
|
|
148
157
|
# # config/initializers/types.rb
|
|
149
|
-
# ActiveRecord::Type.register(:
|
|
158
|
+
# ActiveRecord::Type.register(:price, PriceType)
|
|
150
159
|
#
|
|
151
160
|
# # app/models/store_listing.rb
|
|
152
161
|
# class StoreListing < ActiveRecord::Base
|
|
153
|
-
# attribute :price_in_cents, :
|
|
162
|
+
# attribute :price_in_cents, :price
|
|
154
163
|
# end
|
|
155
164
|
#
|
|
156
165
|
# store_listing = StoreListing.new(price_in_cents: '$10.00')
|
|
@@ -170,13 +179,13 @@ module ActiveRecord
|
|
|
170
179
|
# class Money < Struct.new(:amount, :currency)
|
|
171
180
|
# end
|
|
172
181
|
#
|
|
173
|
-
# class
|
|
182
|
+
# class PriceType < ActiveRecord::Type::Value
|
|
174
183
|
# def initialize(currency_converter:)
|
|
175
184
|
# @currency_converter = currency_converter
|
|
176
185
|
# end
|
|
177
186
|
#
|
|
178
|
-
# # value will be the result of
|
|
179
|
-
# #
|
|
187
|
+
# # value will be the result of #deserialize or
|
|
188
|
+
# # #cast. Assumed to be an instance of Money in
|
|
180
189
|
# # this case.
|
|
181
190
|
# def serialize(value)
|
|
182
191
|
# value_in_bitcoins = @currency_converter.convert_to_bitcoins(value)
|
|
@@ -185,19 +194,19 @@ module ActiveRecord
|
|
|
185
194
|
# end
|
|
186
195
|
#
|
|
187
196
|
# # config/initializers/types.rb
|
|
188
|
-
# ActiveRecord::Type.register(:
|
|
197
|
+
# ActiveRecord::Type.register(:price, PriceType)
|
|
189
198
|
#
|
|
190
199
|
# # app/models/product.rb
|
|
191
200
|
# class Product < ActiveRecord::Base
|
|
192
201
|
# currency_converter = ConversionRatesFromTheInternet.new
|
|
193
|
-
# attribute :price_in_bitcoins, :
|
|
202
|
+
# attribute :price_in_bitcoins, :price, currency_converter: currency_converter
|
|
194
203
|
# end
|
|
195
204
|
#
|
|
196
205
|
# Product.where(price_in_bitcoins: Money.new(5, "USD"))
|
|
197
|
-
# #
|
|
206
|
+
# # SELECT * FROM products WHERE price_in_bitcoins = 0.02230
|
|
198
207
|
#
|
|
199
208
|
# Product.where(price_in_bitcoins: Money.new(5, "GBP"))
|
|
200
|
-
# #
|
|
209
|
+
# # SELECT * FROM products WHERE price_in_bitcoins = 0.03412
|
|
201
210
|
#
|
|
202
211
|
# ==== Dirty Tracking
|
|
203
212
|
#
|
|
@@ -205,51 +214,31 @@ module ActiveRecord
|
|
|
205
214
|
# tracking is performed. The methods +changed?+ and +changed_in_place?+
|
|
206
215
|
# will be called from ActiveModel::Dirty. See the documentation for those
|
|
207
216
|
# methods in ActiveModel::Type::Value for more details.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
reload_schema_from_cache
|
|
213
|
-
|
|
214
|
-
case cast_type
|
|
215
|
-
when Symbol
|
|
216
|
-
cast_type = Type.lookup(cast_type, **options, adapter: Type.adapter_name_from(self))
|
|
217
|
-
when nil
|
|
218
|
-
if (prev_cast_type, prev_default = attributes_to_define_after_schema_loads[name])
|
|
219
|
-
default = prev_default if default == NO_DEFAULT_PROVIDED
|
|
220
|
-
else
|
|
221
|
-
prev_cast_type = -> subtype { subtype }
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
cast_type = if block_given?
|
|
225
|
-
-> subtype { yield Proc === prev_cast_type ? prev_cast_type[subtype] : prev_cast_type }
|
|
226
|
-
else
|
|
227
|
-
prev_cast_type
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
self.attributes_to_define_after_schema_loads =
|
|
232
|
-
attributes_to_define_after_schema_loads.merge(name => [cast_type, default])
|
|
233
|
-
end
|
|
217
|
+
#
|
|
218
|
+
#--
|
|
219
|
+
# Implemented by ActiveModel::AttributeRegistration#attribute.
|
|
234
220
|
|
|
235
|
-
# This
|
|
236
|
-
#
|
|
237
|
-
# waiting for the schema to load. Automatic schema detection and
|
|
238
|
-
# ClassMethods#attribute both call this under the hood. While this method
|
|
221
|
+
# This API only accepts type objects, and will do its work immediately instead of
|
|
222
|
+
# waiting for the schema to load. While this method
|
|
239
223
|
# is provided so it can be used by plugin authors, application code
|
|
240
224
|
# should probably use ClassMethods#attribute.
|
|
241
225
|
#
|
|
242
|
-
#
|
|
226
|
+
# ==== Parameters
|
|
227
|
+
#
|
|
228
|
+
# [+name+]
|
|
229
|
+
# The name of the attribute being defined. Expected to be a +String+.
|
|
243
230
|
#
|
|
244
|
-
# +cast_type+
|
|
231
|
+
# [+cast_type+]
|
|
232
|
+
# The type object to use for this attribute.
|
|
245
233
|
#
|
|
246
|
-
# +default+
|
|
247
|
-
#
|
|
248
|
-
#
|
|
249
|
-
# will be
|
|
234
|
+
# [+default+]
|
|
235
|
+
# The default value to use when no value is provided. If this option
|
|
236
|
+
# is not passed, the previous default value (if any) will be used.
|
|
237
|
+
# Otherwise, the default will be +nil+. A proc can also be passed, and
|
|
238
|
+
# will be called once each time a new value is needed.
|
|
250
239
|
#
|
|
251
|
-
# +user_provided_default+
|
|
252
|
-
# +cast+ or +deserialize+.
|
|
240
|
+
# [+user_provided_default+]
|
|
241
|
+
# Whether the default value should be cast using +cast+ or +deserialize+.
|
|
253
242
|
def define_attribute(
|
|
254
243
|
name,
|
|
255
244
|
cast_type,
|
|
@@ -260,14 +249,38 @@ module ActiveRecord
|
|
|
260
249
|
define_default_attribute(name, default, cast_type, from_user: user_provided_default)
|
|
261
250
|
end
|
|
262
251
|
|
|
263
|
-
def
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
252
|
+
def _default_attributes # :nodoc:
|
|
253
|
+
@default_attributes ||= begin
|
|
254
|
+
attributes_hash = with_connection do |connection|
|
|
255
|
+
columns_hash.transform_values do |column|
|
|
256
|
+
ActiveModel::Attribute.from_database(column.name, column.default, type_for_column(connection, column))
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
attribute_set = ActiveModel::AttributeSet.new(attributes_hash)
|
|
261
|
+
apply_pending_attribute_modifications(attribute_set)
|
|
262
|
+
attribute_set
|
|
268
263
|
end
|
|
269
264
|
end
|
|
270
265
|
|
|
266
|
+
##
|
|
267
|
+
# :method: type_for_attribute
|
|
268
|
+
# :call-seq: type_for_attribute(attribute_name, &block)
|
|
269
|
+
#
|
|
270
|
+
# See ActiveModel::Attributes::ClassMethods#type_for_attribute.
|
|
271
|
+
#
|
|
272
|
+
# This method will access the database and load the model's schema if
|
|
273
|
+
# necessary.
|
|
274
|
+
#--
|
|
275
|
+
# Implemented by ActiveModel::AttributeRegistration::ClassMethods#type_for_attribute.
|
|
276
|
+
|
|
277
|
+
##
|
|
278
|
+
protected
|
|
279
|
+
def reload_schema_from_cache(*)
|
|
280
|
+
reset_default_attributes!
|
|
281
|
+
super
|
|
282
|
+
end
|
|
283
|
+
|
|
271
284
|
private
|
|
272
285
|
NO_DEFAULT_PROVIDED = Object.new # :nodoc:
|
|
273
286
|
private_constant :NO_DEFAULT_PROVIDED
|
|
@@ -287,6 +300,18 @@ module ActiveRecord
|
|
|
287
300
|
end
|
|
288
301
|
_default_attributes[name] = default_attribute
|
|
289
302
|
end
|
|
303
|
+
|
|
304
|
+
def reset_default_attributes
|
|
305
|
+
reload_schema_from_cache
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def resolve_type_name(name, **options)
|
|
309
|
+
Type.lookup(name, **options, adapter: Type.adapter_name_from(self))
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def type_for_column(connection, column)
|
|
313
|
+
hook_attribute_type(column.name, super)
|
|
314
|
+
end
|
|
290
315
|
end
|
|
291
316
|
end
|
|
292
317
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_record/associations/nested_error"
|
|
4
|
+
|
|
3
5
|
module ActiveRecord
|
|
4
6
|
# = Active Record Autosave Association
|
|
5
7
|
#
|
|
@@ -26,7 +28,7 @@ module ActiveRecord
|
|
|
26
28
|
#
|
|
27
29
|
# Child records are validated unless <tt>:validate</tt> is +false+.
|
|
28
30
|
#
|
|
29
|
-
# == Callbacks
|
|
31
|
+
# == \Callbacks
|
|
30
32
|
#
|
|
31
33
|
# Association with autosave option defines several callbacks on your
|
|
32
34
|
# model (around_save, before_save, after_create, after_update). Please note that
|
|
@@ -273,6 +275,11 @@ module ActiveRecord
|
|
|
273
275
|
end
|
|
274
276
|
|
|
275
277
|
private
|
|
278
|
+
def init_internals
|
|
279
|
+
super
|
|
280
|
+
@_already_called = nil
|
|
281
|
+
end
|
|
282
|
+
|
|
276
283
|
# Returns the record for an association collection that should be validated
|
|
277
284
|
# or saved. If +autosave+ is +false+ only new records will be returned,
|
|
278
285
|
# unless the parent is/was a new record itself.
|
|
@@ -310,7 +317,7 @@ module ActiveRecord
|
|
|
310
317
|
def validate_single_association(reflection)
|
|
311
318
|
association = association_instance_get(reflection.name)
|
|
312
319
|
record = association && association.reader
|
|
313
|
-
association_valid?(
|
|
320
|
+
association_valid?(association, record) if record && (record.changed_for_autosave? || custom_validation_context?)
|
|
314
321
|
end
|
|
315
322
|
|
|
316
323
|
# Validate the associated records if <tt>:validate</tt> or
|
|
@@ -319,7 +326,7 @@ module ActiveRecord
|
|
|
319
326
|
def validate_collection_association(reflection)
|
|
320
327
|
if association = association_instance_get(reflection.name)
|
|
321
328
|
if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave])
|
|
322
|
-
records.
|
|
329
|
+
records.each { |record| association_valid?(association, record) }
|
|
323
330
|
end
|
|
324
331
|
end
|
|
325
332
|
end
|
|
@@ -327,38 +334,33 @@ module ActiveRecord
|
|
|
327
334
|
# Returns whether or not the association is valid and applies any errors to
|
|
328
335
|
# the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt>
|
|
329
336
|
# enabled records if they're marked_for_destruction? or destroyed.
|
|
330
|
-
def association_valid?(
|
|
331
|
-
return true if record.destroyed? || (
|
|
337
|
+
def association_valid?(association, record)
|
|
338
|
+
return true if record.destroyed? || (association.options[:autosave] && record.marked_for_destruction?)
|
|
332
339
|
|
|
333
340
|
context = validation_context if custom_validation_context?
|
|
341
|
+
return true if record.valid?(context)
|
|
334
342
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
343
|
+
if context || record.changed_for_autosave?
|
|
344
|
+
associated_errors = record.errors.objects
|
|
345
|
+
else
|
|
346
|
+
# If there are existing invalid records in the DB, we should still be able to reference them.
|
|
347
|
+
# Unless a record (no matter where in the association chain) is invalid and is being changed.
|
|
348
|
+
associated_errors = record.errors.objects.select { |error| error.is_a?(Associations::NestedError) }
|
|
349
|
+
end
|
|
338
350
|
|
|
339
|
-
|
|
340
|
-
|
|
351
|
+
if association.options[:autosave]
|
|
352
|
+
return if equal?(record)
|
|
341
353
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
else
|
|
350
|
-
errors.add(reflection.name)
|
|
351
|
-
end
|
|
354
|
+
associated_errors.each { |error|
|
|
355
|
+
errors.objects.append(
|
|
356
|
+
Associations::NestedError.new(association, error)
|
|
357
|
+
)
|
|
358
|
+
}
|
|
359
|
+
elsif associated_errors.any?
|
|
360
|
+
errors.add(association.reflection.name)
|
|
352
361
|
end
|
|
353
|
-
valid
|
|
354
|
-
end
|
|
355
362
|
|
|
356
|
-
|
|
357
|
-
if indexed_attribute
|
|
358
|
-
"#{reflection.name}[#{index}].#{attribute}"
|
|
359
|
-
else
|
|
360
|
-
"#{reflection.name}.#{attribute}"
|
|
361
|
-
end
|
|
363
|
+
errors.any?
|
|
362
364
|
end
|
|
363
365
|
|
|
364
366
|
# Is used as an around_save callback to check while saving a collection
|
|
@@ -436,7 +438,9 @@ module ActiveRecord
|
|
|
436
438
|
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
|
|
437
439
|
def save_has_one_association(reflection)
|
|
438
440
|
association = association_instance_get(reflection.name)
|
|
439
|
-
|
|
441
|
+
return unless association && association.loaded?
|
|
442
|
+
|
|
443
|
+
record = association.load_target
|
|
440
444
|
|
|
441
445
|
if record && !record.destroyed?
|
|
442
446
|
autosave = reflection.options[:autosave]
|
|
@@ -444,11 +448,18 @@ module ActiveRecord
|
|
|
444
448
|
if autosave && record.marked_for_destruction?
|
|
445
449
|
record.destroy
|
|
446
450
|
elsif autosave != false
|
|
447
|
-
|
|
451
|
+
primary_key = Array(compute_primary_key(reflection, self)).map(&:to_s)
|
|
452
|
+
primary_key_value = primary_key.map { |key| _read_attribute(key) }
|
|
448
453
|
|
|
449
|
-
if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record,
|
|
454
|
+
if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record, primary_key_value)
|
|
450
455
|
unless reflection.through_reflection
|
|
451
|
-
|
|
456
|
+
foreign_key = Array(reflection.foreign_key)
|
|
457
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
|
458
|
+
|
|
459
|
+
primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
|
|
460
|
+
association_id = _read_attribute(primary_key)
|
|
461
|
+
record[foreign_key] = association_id unless record[foreign_key] == association_id
|
|
462
|
+
end
|
|
452
463
|
association.set_inverse_instance(record)
|
|
453
464
|
end
|
|
454
465
|
|
|
@@ -463,14 +474,26 @@ module ActiveRecord
|
|
|
463
474
|
# If the record is new or it has changed, returns true.
|
|
464
475
|
def _record_changed?(reflection, record, key)
|
|
465
476
|
record.new_record? ||
|
|
466
|
-
association_foreign_key_changed?(reflection, record, key) ||
|
|
477
|
+
(association_foreign_key_changed?(reflection, record, key) ||
|
|
478
|
+
inverse_polymorphic_association_changed?(reflection, record)) ||
|
|
467
479
|
record.will_save_change_to_attribute?(reflection.foreign_key)
|
|
468
480
|
end
|
|
469
481
|
|
|
470
482
|
def association_foreign_key_changed?(reflection, record, key)
|
|
471
483
|
return false if reflection.through_reflection?
|
|
472
484
|
|
|
473
|
-
|
|
485
|
+
foreign_key = Array(reflection.foreign_key)
|
|
486
|
+
return false unless foreign_key.all? { |key| record._has_attribute?(key) }
|
|
487
|
+
|
|
488
|
+
foreign_key.map { |key| record._read_attribute(key) } != Array(key)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def inverse_polymorphic_association_changed?(reflection, record)
|
|
492
|
+
return false unless reflection.inverse_of&.polymorphic?
|
|
493
|
+
|
|
494
|
+
class_name = record._read_attribute(reflection.inverse_of.foreign_type)
|
|
495
|
+
|
|
496
|
+
reflection.active_record.polymorphic_name != class_name
|
|
474
497
|
end
|
|
475
498
|
|
|
476
499
|
# Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
|
|
@@ -485,14 +508,21 @@ module ActiveRecord
|
|
|
485
508
|
autosave = reflection.options[:autosave]
|
|
486
509
|
|
|
487
510
|
if autosave && record.marked_for_destruction?
|
|
488
|
-
|
|
511
|
+
foreign_key = Array(reflection.foreign_key)
|
|
512
|
+
foreign_key.each { |key| self[key] = nil }
|
|
489
513
|
record.destroy
|
|
490
514
|
elsif autosave != false
|
|
491
515
|
saved = record.save(validate: !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
|
|
492
516
|
|
|
493
517
|
if association.updated?
|
|
494
|
-
|
|
495
|
-
|
|
518
|
+
primary_key = Array(compute_primary_key(reflection, record)).map(&:to_s)
|
|
519
|
+
foreign_key = Array(reflection.foreign_key)
|
|
520
|
+
|
|
521
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
|
522
|
+
primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
|
|
523
|
+
association_id = record._read_attribute(primary_key)
|
|
524
|
+
self[foreign_key] = association_id unless self[foreign_key] == association_id
|
|
525
|
+
end
|
|
496
526
|
association.loaded!
|
|
497
527
|
end
|
|
498
528
|
|
|
@@ -501,8 +531,20 @@ module ActiveRecord
|
|
|
501
531
|
end
|
|
502
532
|
end
|
|
503
533
|
|
|
504
|
-
def
|
|
505
|
-
|
|
534
|
+
def compute_primary_key(reflection, record)
|
|
535
|
+
if primary_key_options = reflection.options[:primary_key]
|
|
536
|
+
primary_key_options
|
|
537
|
+
elsif reflection.options[:query_constraints] && (query_constraints = record.class.query_constraints_list)
|
|
538
|
+
query_constraints
|
|
539
|
+
elsif record.class.has_query_constraints? && !reflection.options[:foreign_key]
|
|
540
|
+
record.class.query_constraints_list
|
|
541
|
+
elsif record.class.composite_primary_key?
|
|
542
|
+
# If record has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
|
|
543
|
+
primary_key = record.class.primary_key
|
|
544
|
+
primary_key.include?("id") ? "id" : primary_key
|
|
545
|
+
else
|
|
546
|
+
record.class.primary_key
|
|
547
|
+
end
|
|
506
548
|
end
|
|
507
549
|
|
|
508
550
|
def _ensure_no_duplicate_errors
|
data/lib/active_record/base.rb
CHANGED
|
@@ -233,7 +233,7 @@ module ActiveRecord # :nodoc:
|
|
|
233
233
|
#
|
|
234
234
|
# Connections are usually created through
|
|
235
235
|
# {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] and retrieved
|
|
236
|
-
# by ActiveRecord::Base.
|
|
236
|
+
# by ActiveRecord::Base.lease_connection. All classes inheriting from ActiveRecord::Base will use this
|
|
237
237
|
# connection. But you can also set a class-specific connection. For example, if Course is an
|
|
238
238
|
# ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
|
|
239
239
|
# and Course and all of its subclasses will use this connection instead.
|
|
@@ -256,13 +256,13 @@ module ActiveRecord # :nodoc:
|
|
|
256
256
|
# * AssociationTypeMismatch - The object assigned to the association wasn't of the type
|
|
257
257
|
# specified in the association definition.
|
|
258
258
|
# * AttributeAssignmentError - An error occurred while doing a mass assignment through the
|
|
259
|
-
# {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
|
|
259
|
+
# {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=] method.
|
|
260
260
|
# You can inspect the +attribute+ property of the exception object to determine which attribute
|
|
261
261
|
# triggered the error.
|
|
262
262
|
# * ConnectionNotEstablished - No connection has been established.
|
|
263
263
|
# Use {ActiveRecord::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] before querying.
|
|
264
264
|
# * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
|
|
265
|
-
# {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
|
|
265
|
+
# {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=] method.
|
|
266
266
|
# The +errors+ property of this exception contains an array of
|
|
267
267
|
# AttributeAssignmentError
|
|
268
268
|
# objects that should be inspected to determine which attributes triggered the errors.
|
|
@@ -280,7 +280,7 @@ module ActiveRecord # :nodoc:
|
|
|
280
280
|
# So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
|
|
281
281
|
# instances in the current object space.
|
|
282
282
|
class Base
|
|
283
|
-
|
|
283
|
+
include ActiveModel::API
|
|
284
284
|
|
|
285
285
|
extend ActiveSupport::Benchmarkable
|
|
286
286
|
extend ActiveSupport::DescendantsTracker
|
|
@@ -304,18 +304,18 @@ module ActiveRecord # :nodoc:
|
|
|
304
304
|
include Scoping
|
|
305
305
|
include Sanitization
|
|
306
306
|
include AttributeAssignment
|
|
307
|
-
include ActiveModel::Conversion
|
|
308
307
|
include Integration
|
|
309
308
|
include Validations
|
|
310
309
|
include CounterCache
|
|
311
310
|
include Attributes
|
|
312
311
|
include Locking::Optimistic
|
|
313
312
|
include Locking::Pessimistic
|
|
313
|
+
include Encryption::EncryptableRecord
|
|
314
314
|
include AttributeMethods
|
|
315
315
|
include Callbacks
|
|
316
316
|
include Timestamp
|
|
317
317
|
include Associations
|
|
318
|
-
include
|
|
318
|
+
include SecurePassword
|
|
319
319
|
include AutosaveAssociation
|
|
320
320
|
include NestedAttributes
|
|
321
321
|
include Transactions
|
|
@@ -325,9 +325,13 @@ module ActiveRecord # :nodoc:
|
|
|
325
325
|
include Serialization
|
|
326
326
|
include Store
|
|
327
327
|
include SecureToken
|
|
328
|
+
include TokenFor
|
|
328
329
|
include SignedId
|
|
329
330
|
include Suppressor
|
|
330
|
-
include
|
|
331
|
+
include Normalization
|
|
332
|
+
include Marshalling::Methods
|
|
333
|
+
|
|
334
|
+
self.param_delimiter = "_"
|
|
331
335
|
end
|
|
332
336
|
|
|
333
337
|
ActiveSupport.run_load_hooks(:active_record, Base)
|
|
@@ -84,7 +84,7 @@ module ActiveRecord
|
|
|
84
84
|
# == Types of callbacks
|
|
85
85
|
#
|
|
86
86
|
# There are three types of callbacks accepted by the callback macros: method references (symbol), callback objects,
|
|
87
|
-
# inline methods (using a proc). Method references and callback objects are the recommended approaches,
|
|
87
|
+
# inline methods (using a proc). \Method references and callback objects are the recommended approaches,
|
|
88
88
|
# inline methods using a proc are sometimes appropriate (such as for creating mix-ins).
|
|
89
89
|
#
|
|
90
90
|
# The method reference callbacks work by specifying a protected or private method available in the object, like this:
|
|
@@ -173,7 +173,7 @@ module ActiveRecord
|
|
|
173
173
|
#
|
|
174
174
|
# If a <tt>before_*</tt> callback throws +:abort+, all the later callbacks and
|
|
175
175
|
# the associated action are cancelled.
|
|
176
|
-
# Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
|
|
176
|
+
# \Callbacks are generally run in the order they are defined, with the exception of callbacks defined as
|
|
177
177
|
# methods on the model, which are called last.
|
|
178
178
|
#
|
|
179
179
|
# == Ordering callbacks
|
|
@@ -234,30 +234,16 @@ module ActiveRecord
|
|
|
234
234
|
# end
|
|
235
235
|
#
|
|
236
236
|
# In this case the +log_children+ is executed before +do_something_else+.
|
|
237
|
-
#
|
|
237
|
+
# This applies to all non-transactional callbacks, and to +before_commit+.
|
|
238
238
|
#
|
|
239
|
-
#
|
|
240
|
-
#
|
|
239
|
+
# For transactional +after_+ callbacks (+after_commit+, +after_rollback+, etc), the order
|
|
240
|
+
# can be set via configuration.
|
|
241
241
|
#
|
|
242
|
-
#
|
|
243
|
-
#
|
|
244
|
-
# class Topic < ActiveRecord::Base
|
|
245
|
-
# has_many :children
|
|
246
|
-
#
|
|
247
|
-
# after_commit :log_children
|
|
248
|
-
# after_commit :do_something_else
|
|
249
|
-
#
|
|
250
|
-
# private
|
|
251
|
-
# def log_children
|
|
252
|
-
# # Child processing
|
|
253
|
-
# end
|
|
254
|
-
#
|
|
255
|
-
# def do_something_else
|
|
256
|
-
# # Something else
|
|
257
|
-
# end
|
|
258
|
-
# end
|
|
242
|
+
# config.active_record.run_after_transaction_callbacks_in_order_defined = false
|
|
259
243
|
#
|
|
260
|
-
#
|
|
244
|
+
# When set to +true+ (the default from \Rails 7.1), callbacks are executed in the order they
|
|
245
|
+
# are defined, just like the example above. When set to +false+, the order is reversed, so
|
|
246
|
+
# +do_something_else+ is executed before +log_children+.
|
|
261
247
|
#
|
|
262
248
|
# == \Transactions
|
|
263
249
|
#
|
|
@@ -432,7 +418,7 @@ module ActiveRecord
|
|
|
432
418
|
|
|
433
419
|
def destroy # :nodoc:
|
|
434
420
|
@_destroy_callback_already_called ||= false
|
|
435
|
-
return if @_destroy_callback_already_called
|
|
421
|
+
return true if @_destroy_callback_already_called
|
|
436
422
|
@_destroy_callback_already_called = true
|
|
437
423
|
_run_destroy_callbacks { super }
|
|
438
424
|
rescue RecordNotDestroyed => e
|
|
@@ -460,7 +446,7 @@ module ActiveRecord
|
|
|
460
446
|
end
|
|
461
447
|
|
|
462
448
|
def _update_record
|
|
463
|
-
_run_update_callbacks { super }
|
|
449
|
+
_run_update_callbacks { record_update_timestamps { super } }
|
|
464
450
|
end
|
|
465
451
|
end
|
|
466
452
|
end
|