activerecord 7.1.6 → 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 +839 -2248
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +15 -8
- data/lib/active_record/associations/belongs_to_association.rb +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- 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/collection_association.rb +16 -8
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +7 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +2 -1
- 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/singular_association.rb +6 -0
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +59 -292
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +23 -55
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +5 -25
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
- data/lib/active_record/attribute_methods.rb +51 -60
- data/lib/active_record/attributes.rb +93 -68
- data/lib/active_record/autosave_association.rb +25 -32
- data/lib/active_record/base.rb +4 -5
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +24 -107
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +294 -72
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +34 -17
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -75
- data/lib/active_record/connection_adapters/abstract/quoting.rb +65 -91
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +6 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -6
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -62
- data/lib/active_record/connection_adapters/abstract_adapter.rb +46 -44
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +53 -15
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +43 -48
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +6 -0
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +19 -18
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -23
- data/lib/active_record/connection_adapters/pool_config.rb +7 -6
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +27 -4
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +30 -8
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +16 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +36 -26
- data/lib/active_record/connection_adapters/schema_cache.rb +123 -128
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -6
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +133 -78
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +15 -15
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -48
- data/lib/active_record/connection_adapters.rb +121 -0
- data/lib/active_record/connection_handling.rb +68 -49
- data/lib/active_record/core.rb +112 -44
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +19 -4
- data/lib/active_record/database_configurations/hash_config.rb +38 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +42 -18
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +25 -5
- data/lib/active_record/encryption/encryptor.rb +35 -19
- 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 +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/enum.rb +31 -13
- data/lib/active_record/errors.rb +49 -23
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +37 -31
- data/lib/active_record/future_result.rb +8 -4
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +18 -15
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +7 -6
- data/lib/active_record/log_subscriber.rb +0 -21
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +2 -3
- data/lib/active_record/migration/compatibility.rb +5 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +87 -77
- data/lib/active_record/model_schema.rb +31 -68
- data/lib/active_record/nested_attributes.rb +11 -3
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +30 -352
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +19 -0
- data/lib/active_record/querying.rb +25 -13
- data/lib/active_record/railtie.rb +39 -57
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +42 -44
- data/lib/active_record/reflection.rb +98 -36
- data/lib/active_record/relation/batches/batch_enumerator.rb +15 -2
- data/lib/active_record/relation/batches.rb +14 -8
- data/lib/active_record/relation/calculations.rb +127 -89
- data/lib/active_record/relation/delegation.rb +8 -11
- data/lib/active_record/relation/finder_methods.rb +26 -12
- data/lib/active_record/relation/merger.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder.rb +3 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +238 -65
- data/lib/active_record/relation/record_fetch_warning.rb +3 -0
- data/lib/active_record/relation/spawn_methods.rb +2 -18
- data/lib/active_record/relation/where_clause.rb +15 -21
- data/lib/active_record/relation.rb +508 -74
- data/lib/active_record/result.rb +31 -44
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +24 -19
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +48 -20
- data/lib/active_record/schema_migration.rb +30 -14
- data/lib/active_record/scoping/named.rb +1 -0
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +27 -7
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/table_metadata.rb +1 -10
- data/lib/active_record/tasks/database_tasks.rb +69 -41
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +8 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -1
- data/lib/active_record/test_fixtures.rb +86 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +73 -15
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +15 -10
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +148 -39
- 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/nodes/binary.rb +0 -6
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +4 -3
- data/lib/arel/nodes/sql_literal.rb +7 -0
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +7 -3
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +31 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +16 -10
|
@@ -18,74 +18,45 @@ module ActiveRecord
|
|
|
18
18
|
# Returns the primary key column's value. If the primary key is composite,
|
|
19
19
|
# returns an array of the primary key column values.
|
|
20
20
|
def id
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@primary_key.map { |pk| _read_attribute(pk) }
|
|
21
|
+
_read_attribute(@primary_key)
|
|
24
22
|
end
|
|
25
23
|
|
|
26
24
|
def primary_key_values_present? # :nodoc:
|
|
27
|
-
return id.all? if self.class.composite_primary_key?
|
|
28
|
-
|
|
29
25
|
!!id
|
|
30
26
|
end
|
|
31
27
|
|
|
32
28
|
# Sets the primary key column's value. If the primary key is composite,
|
|
33
29
|
# raises TypeError when the set value not enumerable.
|
|
34
30
|
def id=(value)
|
|
35
|
-
|
|
36
|
-
raise TypeError, "Expected value matching #{self.class.primary_key.inspect}, got #{value.inspect}." unless value.is_a?(Enumerable)
|
|
37
|
-
@primary_key.zip(value) { |attr, value| _write_attribute(attr, value) }
|
|
38
|
-
else
|
|
39
|
-
_write_attribute(@primary_key, value)
|
|
40
|
-
end
|
|
31
|
+
_write_attribute(@primary_key, value)
|
|
41
32
|
end
|
|
42
33
|
|
|
43
34
|
# Queries the primary key column's value. If the primary key is composite,
|
|
44
35
|
# all primary key column values must be queryable.
|
|
45
36
|
def id?
|
|
46
|
-
|
|
47
|
-
@primary_key.all? { |col| _query_attribute(col) }
|
|
48
|
-
else
|
|
49
|
-
_query_attribute(@primary_key)
|
|
50
|
-
end
|
|
37
|
+
_query_attribute(@primary_key)
|
|
51
38
|
end
|
|
52
39
|
|
|
53
40
|
# Returns the primary key column's value before type cast. If the primary key is composite,
|
|
54
41
|
# returns an array of primary key column values before type cast.
|
|
55
42
|
def id_before_type_cast
|
|
56
|
-
|
|
57
|
-
@primary_key.map { |col| attribute_before_type_cast(col) }
|
|
58
|
-
else
|
|
59
|
-
attribute_before_type_cast(@primary_key)
|
|
60
|
-
end
|
|
43
|
+
attribute_before_type_cast(@primary_key)
|
|
61
44
|
end
|
|
62
45
|
|
|
63
46
|
# Returns the primary key column's previous value. If the primary key is composite,
|
|
64
47
|
# returns an array of primary key column previous values.
|
|
65
48
|
def id_was
|
|
66
|
-
|
|
67
|
-
@primary_key.map { |col| attribute_was(col) }
|
|
68
|
-
else
|
|
69
|
-
attribute_was(@primary_key)
|
|
70
|
-
end
|
|
49
|
+
attribute_was(@primary_key)
|
|
71
50
|
end
|
|
72
51
|
|
|
73
52
|
# Returns the primary key column's value from the database. If the primary key is composite,
|
|
74
53
|
# returns an array of primary key column values from database.
|
|
75
54
|
def id_in_database
|
|
76
|
-
|
|
77
|
-
@primary_key.map { |col| attribute_in_database(col) }
|
|
78
|
-
else
|
|
79
|
-
attribute_in_database(@primary_key)
|
|
80
|
-
end
|
|
55
|
+
attribute_in_database(@primary_key)
|
|
81
56
|
end
|
|
82
57
|
|
|
83
58
|
def id_for_database # :nodoc:
|
|
84
|
-
|
|
85
|
-
@primary_key.map { |col| @attributes[col].value_for_database }
|
|
86
|
-
else
|
|
87
|
-
@attributes[@primary_key].value_for_database
|
|
88
|
-
end
|
|
59
|
+
@attributes[@primary_key].value_for_database
|
|
89
60
|
end
|
|
90
61
|
|
|
91
62
|
private
|
|
@@ -109,20 +80,19 @@ module ActiveRecord
|
|
|
109
80
|
# Overwriting will negate any effect of the +primary_key_prefix_type+
|
|
110
81
|
# setting, though.
|
|
111
82
|
def primary_key
|
|
112
|
-
if PRIMARY_KEY_NOT_SET.equal?(@primary_key)
|
|
113
|
-
@primary_key = reset_primary_key
|
|
114
|
-
end
|
|
83
|
+
reset_primary_key if PRIMARY_KEY_NOT_SET.equal?(@primary_key)
|
|
115
84
|
@primary_key
|
|
116
85
|
end
|
|
117
86
|
|
|
118
87
|
def composite_primary_key? # :nodoc:
|
|
119
|
-
|
|
88
|
+
reset_primary_key if PRIMARY_KEY_NOT_SET.equal?(@primary_key)
|
|
89
|
+
@composite_primary_key
|
|
120
90
|
end
|
|
121
91
|
|
|
122
92
|
# Returns a quoted version of the primary key name, used to construct
|
|
123
93
|
# SQL statements.
|
|
124
94
|
def quoted_primary_key
|
|
125
|
-
@quoted_primary_key ||=
|
|
95
|
+
@quoted_primary_key ||= adapter_class.quote_column_name(primary_key)
|
|
126
96
|
end
|
|
127
97
|
|
|
128
98
|
def reset_primary_key # :nodoc:
|
|
@@ -138,12 +108,10 @@ module ActiveRecord
|
|
|
138
108
|
base_name.foreign_key(false)
|
|
139
109
|
elsif base_name && primary_key_prefix_type == :table_name_with_underscore
|
|
140
110
|
base_name.foreign_key
|
|
111
|
+
elsif ActiveRecord::Base != self && table_exists?
|
|
112
|
+
schema_cache.primary_keys(table_name)
|
|
141
113
|
else
|
|
142
|
-
|
|
143
|
-
connection.schema_cache.primary_keys(table_name)
|
|
144
|
-
else
|
|
145
|
-
"id"
|
|
146
|
-
end
|
|
114
|
+
"id"
|
|
147
115
|
end
|
|
148
116
|
end
|
|
149
117
|
|
|
@@ -163,25 +131,25 @@ module ActiveRecord
|
|
|
163
131
|
#
|
|
164
132
|
# Project.primary_key # => "foo_id"
|
|
165
133
|
def primary_key=(value)
|
|
166
|
-
@primary_key
|
|
134
|
+
@primary_key = if value.is_a?(Array)
|
|
135
|
+
@composite_primary_key = true
|
|
136
|
+
include CompositePrimaryKey
|
|
137
|
+
@primary_key = value.map { |v| -v.to_s }.freeze
|
|
138
|
+
elsif value
|
|
139
|
+
-value.to_s
|
|
140
|
+
end
|
|
167
141
|
@quoted_primary_key = nil
|
|
168
142
|
@attributes_builder = nil
|
|
169
143
|
end
|
|
170
144
|
|
|
171
145
|
private
|
|
172
|
-
def derive_primary_key(value)
|
|
173
|
-
return unless value
|
|
174
|
-
|
|
175
|
-
return -value.to_s unless value.is_a?(Array)
|
|
176
|
-
|
|
177
|
-
value.map { |v| -v.to_s }.freeze
|
|
178
|
-
end
|
|
179
|
-
|
|
180
146
|
def inherited(base)
|
|
181
147
|
super
|
|
182
148
|
base.class_eval do
|
|
183
149
|
@primary_key = PRIMARY_KEY_NOT_SET
|
|
150
|
+
@composite_primary_key = false
|
|
184
151
|
@quoted_primary_key = nil
|
|
152
|
+
@attributes_builder = nil
|
|
185
153
|
end
|
|
186
154
|
end
|
|
187
155
|
end
|
|
@@ -30,19 +30,7 @@ module ActiveRecord
|
|
|
30
30
|
name = attr_name.to_s
|
|
31
31
|
name = self.class.attribute_aliases[name] || name
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if self.class.composite_primary_key?
|
|
36
|
-
@attributes.fetch_value("id", &block)
|
|
37
|
-
else
|
|
38
|
-
if @primary_key != "id"
|
|
39
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
|
40
|
-
Using read_attribute(:id) to read the primary key value is deprecated.
|
|
41
|
-
Use #id instead.
|
|
42
|
-
MSG
|
|
43
|
-
end
|
|
44
|
-
@attributes.fetch_value(@primary_key, &block)
|
|
45
|
-
end
|
|
33
|
+
@attributes.fetch_value(name, &block)
|
|
46
34
|
end
|
|
47
35
|
|
|
48
36
|
# This method exists to avoid the expensive primary_key check internally, without
|
|
@@ -130,7 +130,7 @@ module ActiveRecord
|
|
|
130
130
|
# silently cast unsupported types to +String+:
|
|
131
131
|
#
|
|
132
132
|
# >> JSON.parse(JSON.dump(Struct.new(:foo)))
|
|
133
|
-
# => "#<Class:0x000000013090b4c0>"
|
|
133
|
+
# # => "#<Class:0x000000013090b4c0>"
|
|
134
134
|
#
|
|
135
135
|
# ==== Examples
|
|
136
136
|
#
|
|
@@ -180,29 +180,7 @@ module ActiveRecord
|
|
|
180
180
|
# serialize :preferences, coder: Rot13JSON
|
|
181
181
|
# end
|
|
182
182
|
#
|
|
183
|
-
def serialize(attr_name,
|
|
184
|
-
unless class_name_or_coder.nil?
|
|
185
|
-
if class_name_or_coder == ::JSON || [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
|
|
186
|
-
ActiveRecord.deprecator.warn(<<~MSG)
|
|
187
|
-
Passing the coder as positional argument is deprecated and will be removed in Rails 7.2.
|
|
188
|
-
|
|
189
|
-
Please pass the coder as a keyword argument:
|
|
190
|
-
|
|
191
|
-
serialize #{attr_name.inspect}, coder: #{class_name_or_coder}
|
|
192
|
-
MSG
|
|
193
|
-
coder = class_name_or_coder
|
|
194
|
-
else
|
|
195
|
-
ActiveRecord.deprecator.warn(<<~MSG)
|
|
196
|
-
Passing the class as positional argument is deprecated and will be removed in Rails 7.2.
|
|
197
|
-
|
|
198
|
-
Please pass the class as a keyword argument:
|
|
199
|
-
|
|
200
|
-
serialize #{attr_name.inspect}, type: #{class_name_or_coder.name}
|
|
201
|
-
MSG
|
|
202
|
-
type = class_name_or_coder
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
|
|
183
|
+
def serialize(attr_name, coder: nil, type: Object, yaml: {}, **options)
|
|
206
184
|
coder ||= default_column_serializer
|
|
207
185
|
unless coder
|
|
208
186
|
raise ArgumentError, <<~MSG.squish
|
|
@@ -214,7 +192,9 @@ module ActiveRecord
|
|
|
214
192
|
|
|
215
193
|
column_serializer = build_column_serializer(attr_name, coder, type, yaml)
|
|
216
194
|
|
|
217
|
-
attribute(attr_name, **options)
|
|
195
|
+
attribute(attr_name, **options)
|
|
196
|
+
|
|
197
|
+
decorate_attributes([attr_name]) do |attr_name, cast_type|
|
|
218
198
|
if type_incompatible_with_serialize?(cast_type, coder, type)
|
|
219
199
|
raise ColumnNotSerializableError.new(attr_name, cast_type)
|
|
220
200
|
end
|
|
@@ -73,14 +73,15 @@ module ActiveRecord
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
module ClassMethods # :nodoc:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
private
|
|
77
|
+
def hook_attribute_type(name, cast_type)
|
|
78
|
+
if create_time_zone_conversion_attribute?(name, cast_type)
|
|
79
|
+
cast_type = TimeZoneConverter.new(cast_type)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
super
|
|
79
83
|
end
|
|
80
|
-
super
|
|
81
|
-
end
|
|
82
84
|
|
|
83
|
-
private
|
|
84
85
|
def create_time_zone_conversion_attribute?(name, cast_type)
|
|
85
86
|
enabled_for_column = time_zone_aware_attributes &&
|
|
86
87
|
!skip_time_zone_conversion_for_attributes.include?(name.to_sym)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "mutex_m"
|
|
4
3
|
require "active_support/core_ext/enumerable"
|
|
5
4
|
|
|
6
5
|
module ActiveRecord
|
|
@@ -21,10 +20,10 @@ module ActiveRecord
|
|
|
21
20
|
include Serialization
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name
|
|
23
|
+
RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name superclass)
|
|
25
24
|
|
|
26
25
|
class GeneratedAttributeMethods < Module # :nodoc:
|
|
27
|
-
|
|
26
|
+
LOCK = Monitor.new
|
|
28
27
|
end
|
|
29
28
|
|
|
30
29
|
class << self
|
|
@@ -50,6 +49,20 @@ module ActiveRecord
|
|
|
50
49
|
super
|
|
51
50
|
end
|
|
52
51
|
|
|
52
|
+
# Allows you to make aliases for attributes.
|
|
53
|
+
#
|
|
54
|
+
# class Person < ActiveRecord::Base
|
|
55
|
+
# alias_attribute :nickname, :name
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# person = Person.create(name: 'Bob')
|
|
59
|
+
# person.name # => "Bob"
|
|
60
|
+
# person.nickname # => "Bob"
|
|
61
|
+
#
|
|
62
|
+
# The alias can also be used for querying:
|
|
63
|
+
#
|
|
64
|
+
# Person.where(nickname: "Bob")
|
|
65
|
+
# # SELECT "people".* FROM "people" WHERE "people"."name" = "Bob"
|
|
53
66
|
def alias_attribute(new_name, old_name)
|
|
54
67
|
super
|
|
55
68
|
|
|
@@ -64,25 +77,6 @@ module ActiveRecord
|
|
|
64
77
|
# alias attributes in Active Record are lazily generated
|
|
65
78
|
end
|
|
66
79
|
|
|
67
|
-
def generate_alias_attributes # :nodoc:
|
|
68
|
-
superclass.generate_alias_attributes unless superclass == Base
|
|
69
|
-
return false if @alias_attributes_mass_generated
|
|
70
|
-
|
|
71
|
-
generated_attribute_methods.synchronize do
|
|
72
|
-
return if @alias_attributes_mass_generated
|
|
73
|
-
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
|
|
74
|
-
aliases_by_attribute_name.each do |old_name, new_names|
|
|
75
|
-
new_names.each do |new_name|
|
|
76
|
-
generate_alias_attribute_methods(code_generator, new_name, old_name)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
@alias_attributes_mass_generated = true
|
|
82
|
-
end
|
|
83
|
-
true
|
|
84
|
-
end
|
|
85
|
-
|
|
86
80
|
def generate_alias_attribute_methods(code_generator, new_name, old_name) # :nodoc:
|
|
87
81
|
attribute_method_patterns.each do |pattern|
|
|
88
82
|
alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
|
|
@@ -91,64 +85,64 @@ module ActiveRecord
|
|
|
91
85
|
end
|
|
92
86
|
|
|
93
87
|
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name) # :nodoc:
|
|
94
|
-
method_name = pattern.method_name(new_name).to_s
|
|
95
|
-
target_name = pattern.method_name(old_name).to_s
|
|
96
88
|
old_name = old_name.to_s
|
|
97
89
|
|
|
98
|
-
method_defined = method_defined?(target_name) || private_method_defined?(target_name)
|
|
99
|
-
manually_defined = method_defined &&
|
|
100
|
-
!self.instance_method(target_name).owner.is_a?(GeneratedAttributeMethods)
|
|
101
|
-
reserved_method_name = ::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(target_name)
|
|
102
|
-
|
|
103
90
|
if !abstract_class? && !has_attribute?(old_name)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if should_warn
|
|
107
|
-
ActiveRecord.deprecator.warn(
|
|
108
|
-
"#{self} model aliases `#{old_name}`, but `#{old_name}` is not an attribute. " \
|
|
109
|
-
"Starting in Rails 7.2, alias_attribute with non-attribute targets will raise. " \
|
|
110
|
-
"Use `alias_method :#{new_name}, :#{old_name}` or define the method manually."
|
|
111
|
-
)
|
|
112
|
-
end
|
|
113
|
-
super
|
|
114
|
-
elsif manually_defined && !reserved_method_name
|
|
115
|
-
aliased_method_redefined_as_well = method_defined_within?(method_name, self)
|
|
116
|
-
return if aliased_method_redefined_as_well
|
|
117
|
-
|
|
118
|
-
ActiveRecord.deprecator.warn(
|
|
119
|
-
"#{self} model aliases `#{old_name}` and has a method called `#{target_name}` defined. " \
|
|
120
|
-
"Starting in Rails 7.2 `#{method_name}` will not be calling `#{target_name}` anymore. " \
|
|
121
|
-
"You may want to additionally define `#{method_name}` to preserve the current behavior."
|
|
122
|
-
)
|
|
123
|
-
super
|
|
91
|
+
raise ArgumentError, "#{self.name} model aliases `#{old_name}`, but `#{old_name}` is not an attribute. " \
|
|
92
|
+
"Use `alias_method :#{new_name}, :#{old_name}` or define the method manually."
|
|
124
93
|
else
|
|
125
94
|
define_attribute_method_pattern(pattern, old_name, owner: code_generator, as: new_name, override: true)
|
|
126
95
|
end
|
|
127
96
|
end
|
|
128
97
|
|
|
98
|
+
def attribute_methods_generated? # :nodoc:
|
|
99
|
+
@attribute_methods_generated
|
|
100
|
+
end
|
|
101
|
+
|
|
129
102
|
# Generates all the attribute related methods for columns in the database
|
|
130
103
|
# accessors, mutators and query methods.
|
|
131
104
|
def define_attribute_methods # :nodoc:
|
|
132
105
|
return false if @attribute_methods_generated
|
|
133
106
|
# Use a mutex; we don't want two threads simultaneously trying to define
|
|
134
107
|
# attribute methods.
|
|
135
|
-
|
|
108
|
+
GeneratedAttributeMethods::LOCK.synchronize do
|
|
136
109
|
return false if @attribute_methods_generated
|
|
110
|
+
|
|
137
111
|
superclass.define_attribute_methods unless base_class?
|
|
138
|
-
|
|
112
|
+
|
|
113
|
+
unless abstract_class?
|
|
114
|
+
load_schema
|
|
115
|
+
super(attribute_names)
|
|
116
|
+
alias_attribute :id_value, :id if _has_attribute?("id") && !_has_attribute?("id_value")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
generate_alias_attributes
|
|
120
|
+
|
|
139
121
|
@attribute_methods_generated = true
|
|
140
122
|
end
|
|
141
123
|
|
|
142
124
|
true
|
|
143
125
|
end
|
|
144
126
|
|
|
145
|
-
def
|
|
146
|
-
|
|
127
|
+
def generate_alias_attributes # :nodoc:
|
|
128
|
+
superclass.generate_alias_attributes unless superclass == Base
|
|
129
|
+
|
|
130
|
+
return if @alias_attributes_mass_generated
|
|
131
|
+
|
|
132
|
+
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
|
|
133
|
+
aliases_by_attribute_name.each do |old_name, new_names|
|
|
134
|
+
new_names.each do |new_name|
|
|
135
|
+
generate_alias_attribute_methods(code_generator, new_name, old_name)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
@alias_attributes_mass_generated = true
|
|
147
141
|
end
|
|
148
142
|
|
|
149
143
|
def undefine_attribute_methods # :nodoc:
|
|
150
|
-
|
|
151
|
-
super if
|
|
144
|
+
GeneratedAttributeMethods::LOCK.synchronize do
|
|
145
|
+
super if @attribute_methods_generated
|
|
152
146
|
@attribute_methods_generated = false
|
|
153
147
|
@alias_attributes_mass_generated = false
|
|
154
148
|
end
|
|
@@ -299,9 +293,7 @@ module ActiveRecord
|
|
|
299
293
|
|
|
300
294
|
# If the result is true then check for the select case.
|
|
301
295
|
# For queries selecting a subset of columns, return false for unselected columns.
|
|
302
|
-
|
|
303
|
-
# have been allocated but not yet initialized.
|
|
304
|
-
if defined?(@attributes)
|
|
296
|
+
if @attributes
|
|
305
297
|
if name = self.class.symbol_column_to_string(name.to_sym)
|
|
306
298
|
return _has_attribute?(name)
|
|
307
299
|
end
|
|
@@ -505,8 +497,7 @@ module ActiveRecord
|
|
|
505
497
|
end
|
|
506
498
|
|
|
507
499
|
def attribute_method?(attr_name)
|
|
508
|
-
|
|
509
|
-
defined?(@attributes) && @attributes.key?(attr_name)
|
|
500
|
+
@attributes&.key?(attr_name)
|
|
510
501
|
end
|
|
511
502
|
|
|
512
503
|
def attributes_with_values(attribute_names)
|