activerecord 7.0.4.3 → 7.1.3.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 +1657 -1274
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +20 -4
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +16 -10
- data/lib/active_record/associations/collection_proxy.rb +20 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -3
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +31 -7
- data/lib/active_record/associations/preloader/through_association.rb +1 -1
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +1 -1
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +327 -222
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +52 -34
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +0 -4
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +108 -26
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +55 -9
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +16 -32
- 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 +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +74 -51
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- 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 +155 -25
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +290 -124
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +509 -102
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +217 -112
- 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 +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +29 -14
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +18 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +75 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.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 +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +15 -8
- 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 +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +362 -60
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +354 -193
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +211 -83
- 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 +262 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +175 -153
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +9 -4
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/disable_joins_association_relation.rb +1 -1
- 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 +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +21 -6
- 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/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +112 -28
- data/lib/active_record/errors.rb +112 -18
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +135 -71
- data/lib/active_record/future_result.rb +31 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +32 -18
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +9 -11
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +105 -7
- data/lib/active_record/migration/compatibility.rb +157 -58
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +271 -114
- data/lib/active_record/model_schema.rb +64 -44
- data/lib/active_record/nested_attributes.rb +24 -6
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +195 -42
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +109 -47
- data/lib/active_record/railties/controller_runtime.rb +14 -9
- data/lib/active_record/railties/databases.rake +142 -148
- 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 +182 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +232 -81
- data/lib/active_record/relation/delegation.rb +23 -9
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +26 -14
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +387 -71
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +91 -35
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +24 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +50 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -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 +7 -5
- data/lib/active_record/store.rb +9 -9
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +27 -15
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- 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 +8 -4
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- 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 +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +1 -1
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/filter.rb +1 -1
- 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/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- 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 +48 -12
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -19,8 +19,6 @@ module ActiveRecord
|
|
19
19
|
|
20
20
|
if value.is_a?(Hash)
|
21
21
|
set_time_zone_without_conversion(super)
|
22
|
-
elsif value.is_a?(Range)
|
23
|
-
Range.new(user_input_in_time_zone(value.begin), user_input_in_time_zone(value.end), value.exclude_end?)
|
24
22
|
elsif value.respond_to?(:in_time_zone)
|
25
23
|
begin
|
26
24
|
super(user_input_in_time_zone(value)) || super
|
@@ -42,8 +40,6 @@ module ActiveRecord
|
|
42
40
|
value.in_time_zone
|
43
41
|
elsif value.respond_to?(:infinite?) && value.infinite?
|
44
42
|
value
|
45
|
-
elsif value.is_a?(Range)
|
46
|
-
Range.new(convert_time_to_time_zone(value.begin), convert_time_to_time_zone(value.end), value.exclude_end?)
|
47
43
|
else
|
48
44
|
map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
|
49
45
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module AttributeMethods
|
5
|
+
# = Active Record Attribute Methods \Write
|
5
6
|
module Write
|
6
7
|
extend ActiveSupport::Concern
|
7
8
|
|
@@ -25,9 +26,8 @@ module ActiveRecord
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
# Updates the attribute identified by
|
29
|
-
#
|
30
|
-
# turned into +nil+.
|
29
|
+
# Updates the attribute identified by +attr_name+ using the specified
|
30
|
+
# +value+. The attribute value will be type cast upon being read.
|
31
31
|
def write_attribute(attr_name, value)
|
32
32
|
name = attr_name.to_s
|
33
33
|
name = self.class.attribute_aliases[name] || name
|
@@ -33,26 +33,94 @@ module ActiveRecord
|
|
33
33
|
Base.instance_methods +
|
34
34
|
Base.private_instance_methods -
|
35
35
|
Base.superclass.instance_methods -
|
36
|
-
Base.superclass.private_instance_methods
|
36
|
+
Base.superclass.private_instance_methods +
|
37
|
+
%i[__id__ dup freeze frozen? hash class clone]
|
37
38
|
).map { |m| -m.to_s }.to_set.freeze
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
41
42
|
module ClassMethods
|
42
|
-
def inherited(child_class) # :nodoc:
|
43
|
-
child_class.initialize_generated_modules
|
44
|
-
super
|
45
|
-
end
|
46
|
-
|
47
43
|
def initialize_generated_modules # :nodoc:
|
48
44
|
@generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
|
49
45
|
private_constant :GeneratedAttributeMethods
|
50
46
|
@attribute_methods_generated = false
|
47
|
+
@alias_attributes_mass_generated = false
|
51
48
|
include @generated_attribute_methods
|
52
49
|
|
53
50
|
super
|
54
51
|
end
|
55
52
|
|
53
|
+
def alias_attribute(new_name, old_name)
|
54
|
+
super
|
55
|
+
|
56
|
+
if @alias_attributes_mass_generated
|
57
|
+
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
|
58
|
+
generate_alias_attribute_methods(code_generator, new_name, old_name)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def eagerly_generate_alias_attribute_methods(_new_name, _old_name) # :nodoc:
|
64
|
+
# alias attributes in Active Record are lazily generated
|
65
|
+
end
|
66
|
+
|
67
|
+
def generate_alias_attributes # :nodoc:
|
68
|
+
superclass.generate_alias_attributes unless superclass == Base
|
69
|
+
return 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
|
+
end
|
84
|
+
|
85
|
+
def alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
|
86
|
+
method_name = pattern.method_name(new_name).to_s
|
87
|
+
target_name = pattern.method_name(old_name).to_s
|
88
|
+
parameters = pattern.parameters
|
89
|
+
old_name = old_name.to_s
|
90
|
+
|
91
|
+
method_defined = method_defined?(target_name) || private_method_defined?(target_name)
|
92
|
+
manually_defined = method_defined &&
|
93
|
+
!self.instance_method(target_name).owner.is_a?(GeneratedAttributeMethods)
|
94
|
+
reserved_method_name = ::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(target_name)
|
95
|
+
|
96
|
+
if !abstract_class? && !has_attribute?(old_name)
|
97
|
+
# We only need to issue this deprecation warning once, so we issue it when defining the original reader method.
|
98
|
+
should_warn = target_name == old_name
|
99
|
+
if should_warn
|
100
|
+
ActiveRecord.deprecator.warn(
|
101
|
+
"#{self} model aliases `#{old_name}`, but `#{old_name}` is not an attribute. " \
|
102
|
+
"Starting in Rails 7.2, alias_attribute with non-attribute targets will raise. " \
|
103
|
+
"Use `alias_method :#{new_name}, :#{old_name}` or define the method manually."
|
104
|
+
)
|
105
|
+
end
|
106
|
+
super
|
107
|
+
elsif manually_defined && !reserved_method_name
|
108
|
+
aliased_method_redefined_as_well = method_defined_within?(method_name, self)
|
109
|
+
return if aliased_method_redefined_as_well
|
110
|
+
|
111
|
+
ActiveRecord.deprecator.warn(
|
112
|
+
"#{self} model aliases `#{old_name}` and has a method called `#{target_name}` defined. " \
|
113
|
+
"Starting in Rails 7.2 `#{method_name}` will not be calling `#{target_name}` anymore. " \
|
114
|
+
"You may want to additionally define `#{method_name}` to preserve the current behavior."
|
115
|
+
)
|
116
|
+
super
|
117
|
+
else
|
118
|
+
define_proxy_call(code_generator, method_name, pattern.proxy_target, parameters, old_name,
|
119
|
+
namespace: :proxy_alias_attribute
|
120
|
+
)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
56
124
|
# Generates all the attribute related methods for columns in the database
|
57
125
|
# accessors, mutators and query methods.
|
58
126
|
def define_attribute_methods # :nodoc:
|
@@ -71,6 +139,7 @@ module ActiveRecord
|
|
71
139
|
generated_attribute_methods.synchronize do
|
72
140
|
super if defined?(@attribute_methods_generated) && @attribute_methods_generated
|
73
141
|
@attribute_methods_generated = false
|
142
|
+
@alias_attributes_mass_generated = false
|
74
143
|
end
|
75
144
|
end
|
76
145
|
|
@@ -186,6 +255,16 @@ module ActiveRecord
|
|
186
255
|
def _has_attribute?(attr_name) # :nodoc:
|
187
256
|
attribute_types.key?(attr_name)
|
188
257
|
end
|
258
|
+
|
259
|
+
private
|
260
|
+
def inherited(child_class)
|
261
|
+
super
|
262
|
+
child_class.initialize_generated_modules
|
263
|
+
child_class.class_eval do
|
264
|
+
@alias_attributes_mass_generated = false
|
265
|
+
@attribute_names = nil
|
266
|
+
end
|
267
|
+
end
|
189
268
|
end
|
190
269
|
|
191
270
|
# A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
|
@@ -309,37 +388,40 @@ module ActiveRecord
|
|
309
388
|
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
|
310
389
|
end
|
311
390
|
|
312
|
-
# Returns the value of the attribute identified by
|
313
|
-
#
|
314
|
-
#
|
315
|
-
#
|
316
|
-
# Note: +:id+ is always present.
|
391
|
+
# Returns the value of the attribute identified by +attr_name+ after it has
|
392
|
+
# been type cast. (For information about specific type casting behavior, see
|
393
|
+
# the types under ActiveModel::Type.)
|
317
394
|
#
|
318
395
|
# class Person < ActiveRecord::Base
|
319
396
|
# belongs_to :organization
|
320
397
|
# end
|
321
398
|
#
|
322
|
-
# person = Person.new(name:
|
323
|
-
# person[:name]
|
324
|
-
# person[:
|
399
|
+
# person = Person.new(name: "Francesco", date_of_birth: "2004-12-12")
|
400
|
+
# person[:name] # => "Francesco"
|
401
|
+
# person[:date_of_birth] # => Date.new(2004, 12, 12)
|
402
|
+
# person[:organization_id] # => nil
|
403
|
+
#
|
404
|
+
# Raises ActiveModel::MissingAttributeError if the attribute is missing.
|
405
|
+
# Note, however, that the +id+ attribute will never be considered missing.
|
325
406
|
#
|
326
|
-
# person = Person.select(
|
327
|
-
# person[:name] # =>
|
328
|
-
# person[:
|
407
|
+
# person = Person.select(:name).first
|
408
|
+
# person[:name] # => "Francesco"
|
409
|
+
# person[:date_of_birth] # => ActiveModel::MissingAttributeError: missing attribute 'date_of_birth' for Person
|
410
|
+
# person[:organization_id] # => ActiveModel::MissingAttributeError: missing attribute 'organization_id' for Person
|
411
|
+
# person[:id] # => nil
|
329
412
|
def [](attr_name)
|
330
413
|
read_attribute(attr_name) { |n| missing_attribute(n, caller) }
|
331
414
|
end
|
332
415
|
|
333
|
-
# Updates the attribute identified by
|
334
|
-
#
|
416
|
+
# Updates the attribute identified by +attr_name+ using the specified
|
417
|
+
# +value+. The attribute value will be type cast upon being read.
|
335
418
|
#
|
336
419
|
# class Person < ActiveRecord::Base
|
337
420
|
# end
|
338
421
|
#
|
339
422
|
# person = Person.new
|
340
|
-
# person[:
|
341
|
-
# person[:
|
342
|
-
# person[:age].class # => Integer
|
423
|
+
# person[:date_of_birth] = "2004-12-12"
|
424
|
+
# person[:date_of_birth] # => Date.new(2004, 12, 12)
|
343
425
|
def []=(attr_name, value)
|
344
426
|
write_attribute(attr_name, value)
|
345
427
|
end
|
@@ -360,10 +442,9 @@ module ActiveRecord
|
|
360
442
|
# end
|
361
443
|
#
|
362
444
|
# private
|
363
|
-
#
|
364
|
-
#
|
365
|
-
#
|
366
|
-
# end
|
445
|
+
# def print_accessed_fields
|
446
|
+
# p @posts.first.accessed_fields
|
447
|
+
# end
|
367
448
|
# end
|
368
449
|
#
|
369
450
|
# Which allows you to quickly change your code to:
|
@@ -392,6 +473,7 @@ module ActiveRecord
|
|
392
473
|
attribute_names &= self.class.column_names
|
393
474
|
attribute_names.delete_if do |name|
|
394
475
|
self.class.readonly_attribute?(name) ||
|
476
|
+
self.class.counter_cache_column?(name) ||
|
395
477
|
column_for_attribute(name).virtual?
|
396
478
|
end
|
397
479
|
end
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
included do
|
11
11
|
class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
|
12
12
|
end
|
13
|
-
|
13
|
+
# = Active Record \Attributes
|
14
14
|
module ClassMethods
|
15
15
|
# Defines an attribute with a type on this model. It will override the
|
16
16
|
# type of existing attributes if needed. This allows control over how
|
@@ -194,10 +194,10 @@ module ActiveRecord
|
|
194
194
|
# end
|
195
195
|
#
|
196
196
|
# Product.where(price_in_bitcoins: Money.new(5, "USD"))
|
197
|
-
# #
|
197
|
+
# # SELECT * FROM products WHERE price_in_bitcoins = 0.02230
|
198
198
|
#
|
199
199
|
# Product.where(price_in_bitcoins: Money.new(5, "GBP"))
|
200
|
-
# #
|
200
|
+
# # SELECT * FROM products WHERE price_in_bitcoins = 0.03412
|
201
201
|
#
|
202
202
|
# ==== Dirty Tracking
|
203
203
|
#
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
#
|
27
27
|
# Child records are validated unless <tt>:validate</tt> is +false+.
|
28
28
|
#
|
29
|
-
# == Callbacks
|
29
|
+
# == \Callbacks
|
30
30
|
#
|
31
31
|
# Association with autosave option defines several callbacks on your
|
32
32
|
# model (around_save, before_save, after_create, after_update). Please note that
|
@@ -273,6 +273,11 @@ module ActiveRecord
|
|
273
273
|
end
|
274
274
|
|
275
275
|
private
|
276
|
+
def init_internals
|
277
|
+
super
|
278
|
+
@_already_called = nil
|
279
|
+
end
|
280
|
+
|
276
281
|
# Returns the record for an association collection that should be validated
|
277
282
|
# or saved. If +autosave+ is +false+ only new records will be returned,
|
278
283
|
# unless the parent is/was a new record itself.
|
@@ -444,11 +449,17 @@ module ActiveRecord
|
|
444
449
|
if autosave && record.marked_for_destruction?
|
445
450
|
record.destroy
|
446
451
|
elsif autosave != false
|
447
|
-
|
452
|
+
primary_key = Array(compute_primary_key(reflection, self)).map(&:to_s)
|
453
|
+
primary_key_value = primary_key.map { |key| _read_attribute(key) }
|
448
454
|
|
449
|
-
if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record,
|
455
|
+
if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record, primary_key_value)
|
450
456
|
unless reflection.through_reflection
|
451
|
-
|
457
|
+
foreign_key = Array(reflection.foreign_key)
|
458
|
+
primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
|
459
|
+
|
460
|
+
primary_key_foreign_key_pairs.each do |primary_key, foreign_key|
|
461
|
+
record[foreign_key] = _read_attribute(primary_key)
|
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 != record.class.polymorphic_class_for(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,6 +531,22 @@ module ActiveRecord
|
|
501
531
|
end
|
502
532
|
end
|
503
533
|
|
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
|
548
|
+
end
|
549
|
+
|
504
550
|
def custom_validation_context?
|
505
551
|
validation_context && [:create, :update].exclude?(validation_context)
|
506
552
|
end
|
data/lib/active_record/base.rb
CHANGED
@@ -311,11 +311,12 @@ module ActiveRecord # :nodoc:
|
|
311
311
|
include Attributes
|
312
312
|
include Locking::Optimistic
|
313
313
|
include Locking::Pessimistic
|
314
|
+
include Encryption::EncryptableRecord
|
314
315
|
include AttributeMethods
|
315
316
|
include Callbacks
|
316
317
|
include Timestamp
|
317
318
|
include Associations
|
318
|
-
include
|
319
|
+
include SecurePassword
|
319
320
|
include AutosaveAssociation
|
320
321
|
include NestedAttributes
|
321
322
|
include Transactions
|
@@ -325,9 +326,13 @@ module ActiveRecord # :nodoc:
|
|
325
326
|
include Serialization
|
326
327
|
include Store
|
327
328
|
include SecureToken
|
329
|
+
include TokenFor
|
328
330
|
include SignedId
|
329
331
|
include Suppressor
|
330
|
-
include
|
332
|
+
include Normalization
|
333
|
+
include Marshalling::Methods
|
334
|
+
|
335
|
+
self.param_delimiter = "_"
|
331
336
|
end
|
332
337
|
|
333
338
|
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
|
@@ -224,42 +224,26 @@ module ActiveRecord
|
|
224
224
|
# after_save :do_something_else
|
225
225
|
#
|
226
226
|
# private
|
227
|
+
# def log_children
|
228
|
+
# # Child processing
|
229
|
+
# end
|
227
230
|
#
|
228
|
-
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
# def do_something_else
|
233
|
-
# # Something else
|
234
|
-
# end
|
231
|
+
# def do_something_else
|
232
|
+
# # Something else
|
233
|
+
# end
|
235
234
|
# end
|
236
235
|
#
|
237
236
|
# In this case the +log_children+ is executed before +do_something_else+.
|
238
|
-
#
|
237
|
+
# This applies to all non-transactional callbacks, and to +before_commit+.
|
239
238
|
#
|
240
|
-
#
|
241
|
-
#
|
239
|
+
# For transactional +after_+ callbacks (+after_commit+, +after_rollback+, etc), the order
|
240
|
+
# can be set via configuration.
|
242
241
|
#
|
243
|
-
#
|
244
|
-
#
|
245
|
-
# class Topic < ActiveRecord::Base
|
246
|
-
# has_many :children
|
247
|
-
#
|
248
|
-
# after_commit :log_children
|
249
|
-
# after_commit :do_something_else
|
250
|
-
#
|
251
|
-
# private
|
252
|
-
#
|
253
|
-
# def log_children
|
254
|
-
# # Child processing
|
255
|
-
# end
|
256
|
-
#
|
257
|
-
# def do_something_else
|
258
|
-
# # Something else
|
259
|
-
# end
|
260
|
-
# end
|
242
|
+
# config.active_record.run_after_transaction_callbacks_in_order_defined = false
|
261
243
|
#
|
262
|
-
#
|
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+.
|
263
247
|
#
|
264
248
|
# == \Transactions
|
265
249
|
#
|
@@ -462,7 +446,7 @@ module ActiveRecord
|
|
462
446
|
end
|
463
447
|
|
464
448
|
def _update_record
|
465
|
-
_run_update_callbacks { super }
|
449
|
+
_run_update_callbacks { record_update_timestamps { super } }
|
466
450
|
end
|
467
451
|
end
|
468
452
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Coders # :nodoc:
|
5
|
+
class ColumnSerializer # :nodoc:
|
6
|
+
attr_reader :object_class
|
7
|
+
attr_reader :coder
|
8
|
+
|
9
|
+
def initialize(attr_name, coder, object_class = Object)
|
10
|
+
@attr_name = attr_name
|
11
|
+
@object_class = object_class
|
12
|
+
@coder = coder
|
13
|
+
check_arity_of_constructor
|
14
|
+
end
|
15
|
+
|
16
|
+
def init_with(coder) # :nodoc:
|
17
|
+
@attr_name = coder["attr_name"]
|
18
|
+
@object_class = coder["object_class"]
|
19
|
+
@coder = coder["coder"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def dump(object)
|
23
|
+
return if object.nil?
|
24
|
+
|
25
|
+
assert_valid_value(object, action: "dump")
|
26
|
+
coder.dump(object)
|
27
|
+
end
|
28
|
+
|
29
|
+
def load(payload)
|
30
|
+
if payload.nil?
|
31
|
+
if @object_class != ::Object
|
32
|
+
return @object_class.new
|
33
|
+
end
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
|
37
|
+
object = coder.load(payload)
|
38
|
+
|
39
|
+
assert_valid_value(object, action: "load")
|
40
|
+
object ||= object_class.new if object_class != Object
|
41
|
+
|
42
|
+
object
|
43
|
+
end
|
44
|
+
|
45
|
+
# Public because it's called by Type::Serialized
|
46
|
+
def assert_valid_value(object, action:)
|
47
|
+
unless object.nil? || object_class === object
|
48
|
+
raise SerializationTypeMismatch,
|
49
|
+
"can't #{action} `#{@attr_name}`: was supposed to be a #{object_class}, but was a #{object.class}. -- #{object.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def check_arity_of_constructor
|
55
|
+
load(nil)
|
56
|
+
rescue ArgumentError
|
57
|
+
raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|