activerecord 6.0.0 → 6.1.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1413 -614
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/active_record/aggregations.rb +5 -6
- data/lib/active_record/association_relation.rb +30 -10
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +55 -29
- data/lib/active_record/associations/association_scope.rb +19 -15
- data/lib/active_record/associations/belongs_to_association.rb +23 -10
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
- data/lib/active_record/associations/builder/association.rb +32 -5
- data/lib/active_record/associations/builder/belongs_to.rb +10 -7
- data/lib/active_record/associations/builder/collection_association.rb +5 -4
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
- data/lib/active_record/associations/builder/has_many.rb +6 -2
- data/lib/active_record/associations/builder/has_one.rb +11 -14
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/collection_association.rb +38 -13
- data/lib/active_record/associations/collection_proxy.rb +14 -7
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +24 -3
- data/lib/active_record/associations/has_many_through_association.rb +10 -4
- data/lib/active_record/associations/has_one_association.rb +15 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +39 -16
- data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
- data/lib/active_record/associations/join_dependency.rb +77 -42
- data/lib/active_record/associations/preloader/association.rb +49 -25
- data/lib/active_record/associations/preloader/through_association.rb +2 -2
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +120 -13
- data/lib/active_record/attribute_assignment.rb +10 -9
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
- data/lib/active_record/attribute_methods/dirty.rb +3 -13
- data/lib/active_record/attribute_methods/primary_key.rb +6 -4
- data/lib/active_record/attribute_methods/query.rb +3 -6
- data/lib/active_record/attribute_methods/read.rb +8 -12
- data/lib/active_record/attribute_methods/serialization.rb +11 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +12 -21
- data/lib/active_record/attribute_methods.rb +64 -54
- data/lib/active_record/attributes.rb +33 -9
- data/lib/active_record/autosave_association.rb +63 -44
- data/lib/active_record/base.rb +2 -14
- data/lib/active_record/callbacks.rb +153 -24
- data/lib/active_record/coders/yaml_column.rb +24 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +202 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
- data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -35
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +145 -52
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
- data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
- data/lib/active_record/connection_adapters/abstract_adapter.rb +76 -79
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
- data/lib/active_record/connection_adapters/column.rb +15 -1
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -36
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -13
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
- data/lib/active_record/connection_adapters/pool_config.rb +73 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -56
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -66
- data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +40 -12
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -57
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +52 -0
- data/lib/active_record/connection_handling.rb +219 -81
- data/lib/active_record/core.rb +283 -71
- data/lib/active_record/counter_cache.rb +4 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
- data/lib/active_record/database_configurations/database_config.rb +52 -9
- data/lib/active_record/database_configurations/hash_config.rb +54 -8
- data/lib/active_record/database_configurations/url_config.rb +15 -41
- data/lib/active_record/database_configurations.rb +125 -85
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +2 -3
- data/lib/active_record/enum.rb +80 -38
- data/lib/active_record/errors.rb +47 -12
- data/lib/active_record/explain.rb +9 -5
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +1 -2
- data/lib/active_record/fixture_set/render_context.rb +1 -1
- data/lib/active_record/fixture_set/table_row.rb +2 -3
- data/lib/active_record/fixture_set/table_rows.rb +0 -1
- data/lib/active_record/fixtures.rb +58 -12
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +40 -21
- data/lib/active_record/insert_all.rb +43 -10
- data/lib/active_record/integration.rb +3 -5
- data/lib/active_record/internal_metadata.rb +18 -7
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +33 -18
- data/lib/active_record/locking/pessimistic.rb +6 -2
- data/lib/active_record/log_subscriber.rb +28 -9
- data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +14 -14
- data/lib/active_record/middleware/database_selector.rb +4 -2
- data/lib/active_record/migration/command_recorder.rb +53 -45
- data/lib/active_record/migration/compatibility.rb +75 -21
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +115 -85
- data/lib/active_record/model_schema.rb +120 -15
- data/lib/active_record/nested_attributes.rb +2 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +50 -46
- data/lib/active_record/query_cache.rb +15 -5
- data/lib/active_record/querying.rb +12 -7
- data/lib/active_record/railtie.rb +65 -45
- data/lib/active_record/railties/console_sandbox.rb +2 -4
- data/lib/active_record/railties/databases.rake +280 -99
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +77 -63
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +38 -32
- data/lib/active_record/relation/calculations.rb +106 -45
- data/lib/active_record/relation/delegation.rb +9 -7
- data/lib/active_record/relation/finder_methods.rb +55 -17
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +27 -26
- data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +59 -40
- data/lib/active_record/relation/query_methods.rb +346 -181
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +8 -8
- data/lib/active_record/relation/where_clause.rb +111 -62
- data/lib/active_record/relation.rb +116 -82
- data/lib/active_record/result.rb +41 -34
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +6 -17
- data/lib/active_record/schema_dumper.rb +34 -4
- data/lib/active_record/schema_migration.rb +2 -8
- data/lib/active_record/scoping/default.rb +1 -4
- data/lib/active_record/scoping/named.rb +7 -18
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +20 -4
- data/lib/active_record/store.rb +9 -4
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +42 -36
- data/lib/active_record/tasks/database_tasks.rb +140 -113
- data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
- data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
- data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
- data/lib/active_record/test_databases.rb +5 -4
- data/lib/active_record/test_fixtures.rb +87 -20
- data/lib/active_record/timestamp.rb +4 -7
- data/lib/active_record/touch_later.rb +20 -21
- data/lib/active_record/transactions.rb +26 -73
- data/lib/active_record/type/adapter_specific_registry.rb +2 -5
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +8 -2
- data/lib/active_record/type_caster/connection.rb +0 -1
- data/lib/active_record/type_caster/map.rb +8 -5
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +24 -4
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +7 -13
- data/lib/arel/attributes/attribute.rb +4 -0
- data/lib/arel/collectors/bind.rb +5 -0
- data/lib/arel/collectors/composite.rb +8 -0
- data/lib/arel/collectors/sql_string.rb +7 -0
- data/lib/arel/collectors/substitute_binds.rb +7 -0
- data/lib/arel/nodes/binary.rb +82 -8
- data/lib/arel/nodes/bind_param.rb +8 -0
- data/lib/arel/nodes/casted.rb +21 -9
- data/lib/arel/nodes/equality.rb +6 -9
- data/lib/arel/nodes/grouping.rb +3 -0
- data/lib/arel/nodes/homogeneous_in.rb +76 -0
- data/lib/arel/nodes/in.rb +8 -1
- data/lib/arel/nodes/infix_operation.rb +13 -1
- data/lib/arel/nodes/join_source.rb +1 -1
- data/lib/arel/nodes/node.rb +7 -6
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/sql_literal.rb +3 -0
- data/lib/arel/nodes/table_alias.rb +7 -3
- data/lib/arel/nodes/unary.rb +0 -1
- data/lib/arel/nodes.rb +3 -1
- data/lib/arel/predications.rb +17 -24
- data/lib/arel/select_manager.rb +1 -2
- data/lib/arel/table.rb +13 -5
- data/lib/arel/visitors/dot.rb +14 -3
- data/lib/arel/visitors/mysql.rb +11 -1
- data/lib/arel/visitors/postgresql.rb +15 -5
- data/lib/arel/visitors/sqlite.rb +0 -1
- data/lib/arel/visitors/to_sql.rb +89 -79
- data/lib/arel/visitors/visitor.rb +0 -1
- data/lib/arel/visitors.rb +0 -7
- data/lib/arel.rb +15 -12
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
- data/lib/rails/generators/active_record/migration.rb +6 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- metadata +31 -27
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
- data/lib/active_record/relation/where_clause_factory.rb +0 -33
- data/lib/arel/attributes.rb +0 -22
- data/lib/arel/visitors/depth_first.rb +0 -204
- data/lib/arel/visitors/ibm_db.rb +0 -34
- data/lib/arel/visitors/informix.rb +0 -62
- data/lib/arel/visitors/mssql.rb +0 -157
- data/lib/arel/visitors/oracle.rb +0 -159
- data/lib/arel/visitors/oracle12.rb +0 -66
- data/lib/arel/visitors/where_sql.rb +0 -23
@@ -2,38 +2,116 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/enumerable"
|
4
4
|
require "active_support/core_ext/string/conversions"
|
5
|
-
require "active_support/core_ext/module/remove_method"
|
6
|
-
require "active_record/errors"
|
7
5
|
|
8
6
|
module ActiveRecord
|
9
7
|
class AssociationNotFoundError < ConfigurationError #:nodoc:
|
8
|
+
attr_reader :record, :association_name
|
10
9
|
def initialize(record = nil, association_name = nil)
|
10
|
+
@record = record
|
11
|
+
@association_name = association_name
|
11
12
|
if record && association_name
|
12
13
|
super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
|
13
14
|
else
|
14
15
|
super("Association was not found.")
|
15
16
|
end
|
16
17
|
end
|
18
|
+
|
19
|
+
class Correction
|
20
|
+
def initialize(error)
|
21
|
+
@error = error
|
22
|
+
end
|
23
|
+
|
24
|
+
def corrections
|
25
|
+
if @error.association_name
|
26
|
+
maybe_these = @error.record.class.reflections.keys
|
27
|
+
|
28
|
+
maybe_these.sort_by { |n|
|
29
|
+
DidYouMean::Jaro.distance(@error.association_name.to_s, n)
|
30
|
+
}.reverse.first(4)
|
31
|
+
else
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# We may not have DYM, and DYM might not let us register error handlers
|
38
|
+
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
39
|
+
DidYouMean.correct_error(self, Correction)
|
40
|
+
end
|
17
41
|
end
|
18
42
|
|
19
43
|
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
44
|
+
attr_reader :reflection, :associated_class
|
20
45
|
def initialize(reflection = nil, associated_class = nil)
|
21
46
|
if reflection
|
47
|
+
@reflection = reflection
|
48
|
+
@associated_class = associated_class.nil? ? reflection.klass : associated_class
|
22
49
|
super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
|
23
50
|
else
|
24
51
|
super("Could not find the inverse association.")
|
25
52
|
end
|
26
53
|
end
|
54
|
+
|
55
|
+
class Correction
|
56
|
+
def initialize(error)
|
57
|
+
@error = error
|
58
|
+
end
|
59
|
+
|
60
|
+
def corrections
|
61
|
+
if @error.reflection && @error.associated_class
|
62
|
+
maybe_these = @error.associated_class.reflections.keys
|
63
|
+
|
64
|
+
maybe_these.sort_by { |n|
|
65
|
+
DidYouMean::Jaro.distance(@error.reflection.options[:inverse_of].to_s, n)
|
66
|
+
}.reverse.first(4)
|
67
|
+
else
|
68
|
+
[]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# We may not have DYM, and DYM might not let us register error handlers
|
74
|
+
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
75
|
+
DidYouMean.correct_error(self, Correction)
|
76
|
+
end
|
27
77
|
end
|
28
78
|
|
29
79
|
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
|
30
|
-
|
31
|
-
|
32
|
-
|
80
|
+
attr_reader :owner_class, :reflection
|
81
|
+
|
82
|
+
def initialize(owner_class = nil, reflection = nil)
|
83
|
+
if owner_class && reflection
|
84
|
+
@owner_class = owner_class
|
85
|
+
@reflection = reflection
|
86
|
+
super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class.name}")
|
33
87
|
else
|
34
88
|
super("Could not find the association.")
|
35
89
|
end
|
36
90
|
end
|
91
|
+
|
92
|
+
class Correction
|
93
|
+
def initialize(error)
|
94
|
+
@error = error
|
95
|
+
end
|
96
|
+
|
97
|
+
def corrections
|
98
|
+
if @error.reflection && @error.owner_class
|
99
|
+
maybe_these = @error.owner_class.reflections.keys
|
100
|
+
maybe_these -= [@error.reflection.name.to_s] # remove failing reflection
|
101
|
+
|
102
|
+
maybe_these.sort_by { |n|
|
103
|
+
DidYouMean::Jaro.distance(@error.reflection.options[:through].to_s, n)
|
104
|
+
}.reverse.first(4)
|
105
|
+
else
|
106
|
+
[]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# We may not have DYM, and DYM might not let us register error handlers
|
112
|
+
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
113
|
+
DidYouMean.correct_error(self, Correction)
|
114
|
+
end
|
37
115
|
end
|
38
116
|
|
39
117
|
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
@@ -92,7 +170,7 @@ module ActiveRecord
|
|
92
170
|
through_reflection = reflection.through_reflection
|
93
171
|
source_reflection_names = reflection.source_reflection_names
|
94
172
|
source_associations = reflection.through_reflection.klass._reflections.keys
|
95
|
-
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or '
|
173
|
+
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')}?")
|
96
174
|
else
|
97
175
|
super("Could not find the source association(s).")
|
98
176
|
end
|
@@ -702,9 +780,8 @@ module ActiveRecord
|
|
702
780
|
# inverse detection only works on #has_many, #has_one, and
|
703
781
|
# #belongs_to associations.
|
704
782
|
#
|
705
|
-
#
|
706
|
-
#
|
707
|
-
# constant, or a custom scope, will also prevent the association's inverse
|
783
|
+
# <tt>:foreign_key</tt> and <tt>:through</tt> options on the associations,
|
784
|
+
# or a custom scope, will also prevent the association's inverse
|
708
785
|
# from being found automatically.
|
709
786
|
#
|
710
787
|
# The automatic guessing of the inverse association uses a heuristic based
|
@@ -1292,7 +1369,11 @@ module ActiveRecord
|
|
1292
1369
|
# similar callbacks may affect the <tt>:dependent</tt> behavior, and the
|
1293
1370
|
# <tt>:dependent</tt> behavior may affect other callbacks.
|
1294
1371
|
#
|
1372
|
+
# * <tt>nil</tt> do nothing (default).
|
1295
1373
|
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
|
1374
|
+
# * <tt>:destroy_async</tt> destroys all the associated objects in a background job. <b>WARNING:</b> Do not use
|
1375
|
+
# this option if the association is backed by foreign key constraints in your database. The foreign key
|
1376
|
+
# constraint actions will occur inside the same transaction that deletes its owner.
|
1296
1377
|
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
|
1297
1378
|
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Polymorphic type will also be nullified
|
1298
1379
|
# on polymorphic associations. Callbacks are not executed.
|
@@ -1357,6 +1438,11 @@ module ActiveRecord
|
|
1357
1438
|
# Specifies a module or array of modules that will be extended into the association object returned.
|
1358
1439
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
1359
1440
|
# association objects.
|
1441
|
+
# [:strict_loading]
|
1442
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
1443
|
+
# [:ensuring_owner_was]
|
1444
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
1445
|
+
# associated records to be deleted in a background job.
|
1360
1446
|
#
|
1361
1447
|
# Option examples:
|
1362
1448
|
# has_many :comments, -> { order("posted_on") }
|
@@ -1367,6 +1453,7 @@ module ActiveRecord
|
|
1367
1453
|
# has_many :tags, as: :taggable
|
1368
1454
|
# has_many :reports, -> { readonly }
|
1369
1455
|
# has_many :subscribers, through: :subscriptions, source: :user
|
1456
|
+
# has_many :comments, strict_loading: true
|
1370
1457
|
def has_many(name, scope = nil, **options, &extension)
|
1371
1458
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
1372
1459
|
Reflection.add_reflection self, name, reflection
|
@@ -1436,7 +1523,11 @@ module ActiveRecord
|
|
1436
1523
|
# Controls what happens to the associated object when
|
1437
1524
|
# its owner is destroyed:
|
1438
1525
|
#
|
1526
|
+
# * <tt>nil</tt> do nothing (default).
|
1439
1527
|
# * <tt>:destroy</tt> causes the associated object to also be destroyed
|
1528
|
+
# * <tt>:destroy_async</tt> causes the associated object to be destroyed in a background job. <b>WARNING:</b> Do not use
|
1529
|
+
# this option if the association is backed by foreign key constraints in your database. The foreign key
|
1530
|
+
# constraint actions will occur inside the same transaction that deletes its owner.
|
1440
1531
|
# * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
|
1441
1532
|
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Polymorphic type column is also nullified
|
1442
1533
|
# on polymorphic associations. Callbacks are not executed.
|
@@ -1495,6 +1586,11 @@ module ActiveRecord
|
|
1495
1586
|
# When set to +true+, the association will also have its presence validated.
|
1496
1587
|
# This will validate the association itself, not the id. You can use
|
1497
1588
|
# +:inverse_of+ to avoid an extra query during validation.
|
1589
|
+
# [:strict_loading]
|
1590
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
1591
|
+
# [:ensuring_owner_was]
|
1592
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
1593
|
+
# associated records to be deleted in a background job.
|
1498
1594
|
#
|
1499
1595
|
# Option examples:
|
1500
1596
|
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
@@ -1507,6 +1603,7 @@ module ActiveRecord
|
|
1507
1603
|
# has_one :club, through: :membership
|
1508
1604
|
# has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
|
1509
1605
|
# has_one :credit_card, required: true
|
1606
|
+
# has_one :credit_card, strict_loading: true
|
1510
1607
|
def has_one(name, scope = nil, **options)
|
1511
1608
|
reflection = Builder::HasOne.build(self, name, scope, options)
|
1512
1609
|
Reflection.add_reflection self, name, reflection
|
@@ -1588,7 +1685,8 @@ module ActiveRecord
|
|
1588
1685
|
# By default this is +id+.
|
1589
1686
|
# [:dependent]
|
1590
1687
|
# If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
|
1591
|
-
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
|
1688
|
+
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. If set to
|
1689
|
+
# <tt>:destroy_async</tt>, the associated object is scheduled to be destroyed in a background job.
|
1592
1690
|
# This option should not be specified when #belongs_to is used in conjunction with
|
1593
1691
|
# a #has_many relationship on another class because of the potential to leave
|
1594
1692
|
# orphaned records behind.
|
@@ -1640,6 +1738,11 @@ module ActiveRecord
|
|
1640
1738
|
# [:default]
|
1641
1739
|
# Provide a callable (i.e. proc or lambda) to specify that the association should
|
1642
1740
|
# be initialized with a particular record before validation.
|
1741
|
+
# [:strict_loading]
|
1742
|
+
# Enforces strict loading every time the associated record is loaded through this association.
|
1743
|
+
# [:ensuring_owner_was]
|
1744
|
+
# Specifies an instance method to be called on the owner. The method must return true in order for the
|
1745
|
+
# associated records to be deleted in a background job.
|
1643
1746
|
#
|
1644
1747
|
# Option examples:
|
1645
1748
|
# belongs_to :firm, foreign_key: "client_of"
|
@@ -1654,6 +1757,7 @@ module ActiveRecord
|
|
1654
1757
|
# belongs_to :company, touch: :employees_last_updated_at
|
1655
1758
|
# belongs_to :user, optional: true
|
1656
1759
|
# belongs_to :account, default: -> { company.account }
|
1760
|
+
# belongs_to :account, strict_loading: true
|
1657
1761
|
def belongs_to(name, scope = nil, **options)
|
1658
1762
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
1659
1763
|
Reflection.add_reflection self, name, reflection
|
@@ -1676,7 +1780,7 @@ module ActiveRecord
|
|
1676
1780
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
1677
1781
|
# join table with a migration such as this:
|
1678
1782
|
#
|
1679
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[
|
1783
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[6.0]
|
1680
1784
|
# def change
|
1681
1785
|
# create_join_table :developers, :projects
|
1682
1786
|
# end
|
@@ -1816,6 +1920,8 @@ module ActiveRecord
|
|
1816
1920
|
#
|
1817
1921
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
1818
1922
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
1923
|
+
# [:strict_loading]
|
1924
|
+
# Enforces strict loading every time an associated record is loaded through this association.
|
1819
1925
|
#
|
1820
1926
|
# Option examples:
|
1821
1927
|
# has_and_belongs_to_many :projects
|
@@ -1823,6 +1929,7 @@ module ActiveRecord
|
|
1823
1929
|
# has_and_belongs_to_many :nations, class_name: "Country"
|
1824
1930
|
# has_and_belongs_to_many :categories, join_table: "prods_cats"
|
1825
1931
|
# has_and_belongs_to_many :categories, -> { readonly }
|
1932
|
+
# has_and_belongs_to_many :categories, strict_loading: true
|
1826
1933
|
def has_and_belongs_to_many(name, scope = nil, **options, &extension)
|
1827
1934
|
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
1828
1935
|
|
@@ -1853,11 +1960,11 @@ module ActiveRecord
|
|
1853
1960
|
hm_options[:through] = middle_reflection.name
|
1854
1961
|
hm_options[:source] = join_model.right_reflection.name
|
1855
1962
|
|
1856
|
-
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
|
1963
|
+
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
|
1857
1964
|
hm_options[k] = options[k] if options.key? k
|
1858
1965
|
end
|
1859
1966
|
|
1860
|
-
has_many name, scope, hm_options, &extension
|
1967
|
+
has_many name, scope, **hm_options, &extension
|
1861
1968
|
_reflections[name.to_s].parent_reflection = habtm_reflection
|
1862
1969
|
end
|
1863
1970
|
end
|
@@ -7,22 +7,23 @@ module ActiveRecord
|
|
7
7
|
include ActiveModel::AttributeAssignment
|
8
8
|
|
9
9
|
private
|
10
|
-
|
11
10
|
def _assign_attributes(attributes)
|
12
|
-
multi_parameter_attributes
|
13
|
-
nested_parameter_attributes = {}
|
11
|
+
multi_parameter_attributes = nested_parameter_attributes = nil
|
14
12
|
|
15
13
|
attributes.each do |k, v|
|
16
|
-
|
17
|
-
|
14
|
+
key = k.to_s
|
15
|
+
|
16
|
+
if key.include?("(")
|
17
|
+
(multi_parameter_attributes ||= {})[key] = v
|
18
18
|
elsif v.is_a?(Hash)
|
19
|
-
nested_parameter_attributes[
|
19
|
+
(nested_parameter_attributes ||= {})[key] = v
|
20
|
+
else
|
21
|
+
_assign_attribute(key, v)
|
20
22
|
end
|
21
23
|
end
|
22
|
-
super(attributes)
|
23
24
|
|
24
|
-
assign_nested_parameter_attributes(nested_parameter_attributes)
|
25
|
-
assign_multiparameter_attributes(multi_parameter_attributes)
|
25
|
+
assign_nested_parameter_attributes(nested_parameter_attributes) if nested_parameter_attributes
|
26
|
+
assign_multiparameter_attributes(multi_parameter_attributes) if multi_parameter_attributes
|
26
27
|
end
|
27
28
|
|
28
29
|
# Assign any deferred nested attributes after the base attributes have been set.
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
extend ActiveSupport::Concern
|
30
30
|
|
31
31
|
included do
|
32
|
-
attribute_method_suffix "_before_type_cast"
|
32
|
+
attribute_method_suffix "_before_type_cast", "_for_database"
|
33
33
|
attribute_method_suffix "_came_from_user?"
|
34
34
|
end
|
35
35
|
|
@@ -46,8 +46,10 @@ module ActiveRecord
|
|
46
46
|
# task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
|
47
47
|
# task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21"
|
48
48
|
def read_attribute_before_type_cast(attr_name)
|
49
|
-
|
50
|
-
|
49
|
+
name = attr_name.to_s
|
50
|
+
name = self.class.attribute_aliases[name] || name
|
51
|
+
|
52
|
+
attribute_before_type_cast(name)
|
51
53
|
end
|
52
54
|
|
53
55
|
# Returns a hash of attributes before typecasting and deserialization.
|
@@ -61,20 +63,21 @@ module ActiveRecord
|
|
61
63
|
# task.attributes_before_type_cast
|
62
64
|
# # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
|
63
65
|
def attributes_before_type_cast
|
64
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
65
66
|
@attributes.values_before_type_cast
|
66
67
|
end
|
67
68
|
|
68
69
|
private
|
69
|
-
|
70
70
|
# Dispatch target for <tt>*_before_type_cast</tt> attribute methods.
|
71
|
-
def attribute_before_type_cast(
|
72
|
-
|
71
|
+
def attribute_before_type_cast(attr_name)
|
72
|
+
@attributes[attr_name].value_before_type_cast
|
73
|
+
end
|
74
|
+
|
75
|
+
def attribute_for_database(attr_name)
|
76
|
+
@attributes[attr_name].value_for_database
|
73
77
|
end
|
74
78
|
|
75
|
-
def attribute_came_from_user?(
|
76
|
-
|
77
|
-
@attributes[attribute_name].came_from_user?
|
79
|
+
def attribute_came_from_user?(attr_name)
|
80
|
+
@attributes[attr_name].came_from_user?
|
78
81
|
end
|
79
82
|
end
|
80
83
|
end
|
@@ -49,7 +49,7 @@ module ActiveRecord
|
|
49
49
|
# +to+ When passed, this method will return false unless the value was
|
50
50
|
# changed to the given value
|
51
51
|
def saved_change_to_attribute?(attr_name, **options)
|
52
|
-
mutations_before_last_save.changed?(attr_name.to_s, options)
|
52
|
+
mutations_before_last_save.changed?(attr_name.to_s, **options)
|
53
53
|
end
|
54
54
|
|
55
55
|
# Returns the change to an attribute during the last save. If the
|
@@ -89,7 +89,7 @@ module ActiveRecord
|
|
89
89
|
# This method is useful in validations and before callbacks to determine
|
90
90
|
# if the next call to +save+ will change a particular attribute. It can be
|
91
91
|
# invoked as +will_save_change_to_name?+ instead of
|
92
|
-
# <tt>will_save_change_to_attribute("name")</tt>.
|
92
|
+
# <tt>will_save_change_to_attribute?("name")</tt>.
|
93
93
|
#
|
94
94
|
# ==== Options
|
95
95
|
#
|
@@ -99,7 +99,7 @@ module ActiveRecord
|
|
99
99
|
# +to+ When passed, this method will return false unless the value will be
|
100
100
|
# changed to the given value
|
101
101
|
def will_save_change_to_attribute?(attr_name, **options)
|
102
|
-
mutations_from_database.changed?(attr_name.to_s, options)
|
102
|
+
mutations_from_database.changed?(attr_name.to_s, **options)
|
103
103
|
end
|
104
104
|
|
105
105
|
# Returns the change to an attribute that will be persisted during the
|
@@ -156,16 +156,6 @@ module ActiveRecord
|
|
156
156
|
end
|
157
157
|
|
158
158
|
private
|
159
|
-
def mutations_from_database
|
160
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
161
|
-
super
|
162
|
-
end
|
163
|
-
|
164
|
-
def mutations_before_last_save
|
165
|
-
sync_with_transaction_state if @transaction_state&.finalized?
|
166
|
-
super
|
167
|
-
end
|
168
|
-
|
169
159
|
def write_attribute_without_type_cast(attr_name, value)
|
170
160
|
result = super
|
171
161
|
clear_attribute_change(attr_name)
|
@@ -31,7 +31,7 @@ module ActiveRecord
|
|
31
31
|
|
32
32
|
# Returns the primary key column's value before type cast.
|
33
33
|
def id_before_type_cast
|
34
|
-
|
34
|
+
attribute_before_type_cast(@primary_key)
|
35
35
|
end
|
36
36
|
|
37
37
|
# Returns the primary key column's previous value.
|
@@ -44,14 +44,17 @@ module ActiveRecord
|
|
44
44
|
attribute_in_database(@primary_key)
|
45
45
|
end
|
46
46
|
|
47
|
-
|
47
|
+
def id_for_database # :nodoc:
|
48
|
+
@attributes[@primary_key].value_for_database
|
49
|
+
end
|
48
50
|
|
51
|
+
private
|
49
52
|
def attribute_method?(attr_name)
|
50
53
|
attr_name == "id" || super
|
51
54
|
end
|
52
55
|
|
53
56
|
module ClassMethods
|
54
|
-
ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database).to_set
|
57
|
+
ID_ATTRIBUTE_METHODS = %w(id id= id? id_before_type_cast id_was id_in_database id_for_database).to_set
|
55
58
|
|
56
59
|
def instance_method_already_implemented?(method_name)
|
57
60
|
super || primary_key && ID_ATTRIBUTE_METHODS.include?(method_name)
|
@@ -120,7 +123,6 @@ module ActiveRecord
|
|
120
123
|
end
|
121
124
|
|
122
125
|
private
|
123
|
-
|
124
126
|
def suppress_composite_primary_key(pk)
|
125
127
|
return pk unless pk.is_a?(Array)
|
126
128
|
|
@@ -17,7 +17,7 @@ module ActiveRecord
|
|
17
17
|
when false, nil then false
|
18
18
|
else
|
19
19
|
if !type_for_attribute(attr_name) { false }
|
20
|
-
if Numeric === value || value
|
20
|
+
if Numeric === value || !value.match?(/[^0-9]/)
|
21
21
|
!value.to_i.zero?
|
22
22
|
else
|
23
23
|
return false if ActiveModel::Type::Boolean::FALSE_VALUES.include?(value)
|
@@ -31,11 +31,8 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
def attribute?(attribute_name)
|
37
|
-
query_attribute(attribute_name)
|
38
|
-
end
|
34
|
+
alias :attribute? :query_attribute
|
35
|
+
private :attribute?
|
39
36
|
end
|
40
37
|
end
|
41
38
|
end
|
@@ -7,17 +7,14 @@ module ActiveRecord
|
|
7
7
|
|
8
8
|
module ClassMethods # :nodoc:
|
9
9
|
private
|
10
|
-
|
11
|
-
def define_method_attribute(name)
|
10
|
+
def define_method_attribute(name, owner:)
|
12
11
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
13
|
-
|
12
|
+
owner, name
|
14
13
|
) do |temp_method_name, attr_name_expr|
|
15
|
-
|
16
|
-
def #{temp_method_name}
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
RUBY
|
14
|
+
owner <<
|
15
|
+
"def #{temp_method_name}" <<
|
16
|
+
" _read_attribute(#{attr_name_expr}) { |n| missing_attribute(n, caller) }" <<
|
17
|
+
"end"
|
21
18
|
end
|
22
19
|
end
|
23
20
|
end
|
@@ -30,14 +27,13 @@ module ActiveRecord
|
|
30
27
|
name = self.class.attribute_aliases[name] || name
|
31
28
|
|
32
29
|
name = @primary_key if name == "id" && @primary_key
|
33
|
-
|
30
|
+
@attributes.fetch_value(name, &block)
|
34
31
|
end
|
35
32
|
|
36
33
|
# This method exists to avoid the expensive primary_key check internally, without
|
37
34
|
# breaking compatibility with the read_attribute API
|
38
35
|
def _read_attribute(attr_name, &block) # :nodoc
|
39
|
-
|
40
|
-
@attributes.fetch_value(attr_name.to_s, &block)
|
36
|
+
@attributes.fetch_value(attr_name, &block)
|
41
37
|
end
|
42
38
|
|
43
39
|
alias :attribute :_read_attribute
|
@@ -41,6 +41,12 @@ module ActiveRecord
|
|
41
41
|
# * +class_name_or_coder+ - Optional, a coder object, which responds to +.load+ and +.dump+
|
42
42
|
# or a class name that the object type should be equal to.
|
43
43
|
#
|
44
|
+
# ==== Options
|
45
|
+
#
|
46
|
+
# +default+ The default value to use when no value is provided. If this option
|
47
|
+
# is not passed, the previous default value (if any) will be used.
|
48
|
+
# Otherwise, the default will be +nil+.
|
49
|
+
#
|
44
50
|
# ==== Example
|
45
51
|
#
|
46
52
|
# # Serialize a preferences attribute.
|
@@ -57,7 +63,7 @@ module ActiveRecord
|
|
57
63
|
# class User < ActiveRecord::Base
|
58
64
|
# serialize :preferences, Hash
|
59
65
|
# end
|
60
|
-
def serialize(attr_name, class_name_or_coder = Object)
|
66
|
+
def serialize(attr_name, class_name_or_coder = Object, **options)
|
61
67
|
# When ::JSON is used, force it to go through the Active Support JSON encoder
|
62
68
|
# to ensure special objects (e.g. Active Record models) are dumped correctly
|
63
69
|
# using the #as_json hook.
|
@@ -69,17 +75,16 @@ module ActiveRecord
|
|
69
75
|
Coders::YAMLColumn.new(attr_name, class_name_or_coder)
|
70
76
|
end
|
71
77
|
|
72
|
-
decorate_attribute_type(attr_name,
|
73
|
-
if type_incompatible_with_serialize?(
|
74
|
-
raise ColumnNotSerializableError.new(attr_name,
|
78
|
+
decorate_attribute_type(attr_name.to_s, **options) do |cast_type|
|
79
|
+
if type_incompatible_with_serialize?(cast_type, class_name_or_coder)
|
80
|
+
raise ColumnNotSerializableError.new(attr_name, cast_type)
|
75
81
|
end
|
76
82
|
|
77
|
-
Type::Serialized.new(
|
83
|
+
Type::Serialized.new(cast_type, coder)
|
78
84
|
end
|
79
85
|
end
|
80
86
|
|
81
87
|
private
|
82
|
-
|
83
88
|
def type_incompatible_with_serialize?(type, class_name)
|
84
89
|
type.is_a?(ActiveRecord::Type::Json) && class_name == ::JSON ||
|
85
90
|
type.respond_to?(:type_cast_array, true) && class_name == ::Array
|
@@ -1,9 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/object/try"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module AttributeMethods
|
5
7
|
module TimeZoneConversion
|
6
8
|
class TimeZoneConverter < DelegateClass(Type::Value) # :nodoc:
|
9
|
+
def self.new(subtype)
|
10
|
+
self === subtype ? subtype : super
|
11
|
+
end
|
12
|
+
|
7
13
|
def deserialize(value)
|
8
14
|
convert_time_to_time_zone(super)
|
9
15
|
end
|
@@ -25,7 +31,6 @@ module ActiveRecord
|
|
25
31
|
end
|
26
32
|
|
27
33
|
private
|
28
|
-
|
29
34
|
def convert_time_to_time_zone(value)
|
30
35
|
return if value.nil?
|
31
36
|
|
@@ -63,22 +68,14 @@ module ActiveRecord
|
|
63
68
|
end
|
64
69
|
|
65
70
|
module ClassMethods # :nodoc:
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
super
|
70
|
-
# We need to apply this decorator here, rather than on module inclusion. The closure
|
71
|
-
# created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
|
72
|
-
# sub class being decorated. As such, changes to `time_zone_aware_attributes`, or
|
73
|
-
# `skip_time_zone_conversion_for_attributes` would not be picked up.
|
74
|
-
subclass.class_eval do
|
75
|
-
matcher = ->(name, type) { create_time_zone_conversion_attribute?(name, type) }
|
76
|
-
decorate_matching_attribute_types(matcher, "_time_zone_conversion") do |type|
|
77
|
-
TimeZoneConverter.new(type)
|
78
|
-
end
|
79
|
-
end
|
71
|
+
def define_attribute(name, cast_type, **)
|
72
|
+
if create_time_zone_conversion_attribute?(name, cast_type)
|
73
|
+
cast_type = TimeZoneConverter.new(cast_type)
|
80
74
|
end
|
75
|
+
super
|
76
|
+
end
|
81
77
|
|
78
|
+
private
|
82
79
|
def create_time_zone_conversion_attribute?(name, cast_type)
|
83
80
|
enabled_for_column = time_zone_aware_attributes &&
|
84
81
|
!skip_time_zone_conversion_for_attributes.include?(name.to_sym)
|
@@ -11,17 +11,14 @@ module ActiveRecord
|
|
11
11
|
|
12
12
|
module ClassMethods # :nodoc:
|
13
13
|
private
|
14
|
-
|
15
|
-
def define_method_attribute=(name)
|
14
|
+
def define_method_attribute=(name, owner:)
|
16
15
|
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
17
|
-
|
16
|
+
owner, name, writer: true,
|
18
17
|
) do |temp_method_name, attr_name_expr|
|
19
|
-
|
20
|
-
def #{temp_method_name}(value)
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
RUBY
|
18
|
+
owner <<
|
19
|
+
"def #{temp_method_name}(value)" <<
|
20
|
+
" _write_attribute(#{attr_name_expr}, value)" <<
|
21
|
+
"end"
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
@@ -34,27 +31,21 @@ module ActiveRecord
|
|
34
31
|
name = self.class.attribute_aliases[name] || name
|
35
32
|
|
36
33
|
name = @primary_key if name == "id" && @primary_key
|
37
|
-
|
34
|
+
@attributes.write_from_user(name, value)
|
38
35
|
end
|
39
36
|
|
40
37
|
# This method exists to avoid the expensive primary_key check internally, without
|
41
38
|
# breaking compatibility with the write_attribute API
|
42
39
|
def _write_attribute(attr_name, value) # :nodoc:
|
43
|
-
|
44
|
-
@attributes.write_from_user(attr_name.to_s, value)
|
45
|
-
value
|
40
|
+
@attributes.write_from_user(attr_name, value)
|
46
41
|
end
|
47
42
|
|
43
|
+
alias :attribute= :_write_attribute
|
44
|
+
private :attribute=
|
45
|
+
|
48
46
|
private
|
49
47
|
def write_attribute_without_type_cast(attr_name, value)
|
50
|
-
|
51
|
-
@attributes.write_cast_value(attr_name.to_s, value)
|
52
|
-
value
|
53
|
-
end
|
54
|
-
|
55
|
-
# Dispatch target for <tt>*=</tt> attribute methods.
|
56
|
-
def attribute=(attribute_name, value)
|
57
|
-
_write_attribute(attribute_name, value)
|
48
|
+
@attributes.write_cast_value(attr_name, value)
|
58
49
|
end
|
59
50
|
end
|
60
51
|
end
|