activerecord 8.0.0 → 8.1.4
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 +1381 -241
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -17
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +20 -4
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +36 -8
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +9 -5
- data/lib/active_record/associations/collection_proxy.rb +26 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +5 -4
- data/lib/active_record/associations/preloader/association.rb +1 -1
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations.rb +159 -21
- data/lib/active_record/attribute_methods/primary_key.rb +2 -1
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +19 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +10 -2
- data/lib/active_record/attribute_methods.rb +24 -17
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +22 -12
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/column_serializer.rb +1 -1
- data/lib/active_record/coders/json.rb +16 -6
- data/lib/active_record/coders/yaml_column.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +19 -18
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +474 -112
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +68 -41
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +31 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +94 -28
- data/lib/active_record/connection_adapters/abstract/transaction.rb +25 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -64
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +133 -40
- data/lib/active_record/connection_adapters/column.rb +14 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +40 -25
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +66 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +29 -33
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +70 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +99 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +40 -12
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -23
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +15 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +7 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +68 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +8 -3
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +16 -2
- data/lib/active_record/connection_adapters.rb +1 -0
- data/lib/active_record/connection_handling.rb +15 -10
- data/lib/active_record/core.rb +44 -12
- data/lib/active_record/counter_cache.rb +36 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +5 -1
- data/lib/active_record/database_configurations/hash_config.rb +66 -9
- data/lib/active_record/database_configurations/url_config.rb +15 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/disable_joins_association_relation.rb +5 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
- data/lib/active_record/encryption/encryptor.rb +39 -25
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +37 -20
- data/lib/active_record/errors.rb +23 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +76 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -2
- data/lib/active_record/future_result.rb +5 -3
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +9 -4
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +7 -0
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +30 -22
- data/lib/active_record/message_pack.rb +13 -0
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +32 -6
- data/lib/active_record/migration/compatibility.rb +34 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +31 -21
- data/lib/active_record/model_schema.rb +38 -12
- data/lib/active_record/nested_attributes.rb +10 -6
- data/lib/active_record/persistence.rb +35 -3
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +7 -7
- data/lib/active_record/querying.rb +17 -5
- data/lib/active_record/railtie.rb +35 -6
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +24 -20
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +36 -1
- data/lib/active_record/relation/batches.rb +25 -11
- data/lib/active_record/relation/calculations.rb +62 -41
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +76 -45
- data/lib/active_record/relation/merger.rb +4 -2
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -7
- data/lib/active_record/relation/predicate_builder.rb +10 -8
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +106 -45
- data/lib/active_record/relation/spawn_methods.rb +6 -6
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +63 -31
- data/lib/active_record/result.rb +44 -21
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +2 -0
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +41 -21
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +48 -19
- data/lib/active_record/statement_cache.rb +16 -12
- data/lib/active_record/store.rb +46 -19
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +5 -20
- data/lib/active_record/tasks/abstract_tasks.rb +83 -0
- data/lib/active_record/tasks/database_tasks.rb +44 -45
- data/lib/active_record/tasks/mysql_database_tasks.rb +4 -56
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
- data/lib/active_record/test_databases.rb +18 -4
- data/lib/active_record/test_fixtures.rb +40 -6
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +58 -32
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record.rb +72 -7
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +7 -23
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +16 -15
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
|
@@ -38,41 +38,39 @@ module ActiveRecord
|
|
|
38
38
|
chain << [reflection, table]
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
klass = reflection.klass
|
|
41
|
+
# The chain starts with the target table, but we want to end with it here (makes
|
|
42
|
+
# more sense in this context), so we reverse
|
|
43
|
+
chain.reverse_each do |reflection, table|
|
|
44
|
+
klass = reflection.klass
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
unless scope.references_values.empty?
|
|
49
|
+
associations = scope.eager_load_values | scope.includes_values
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
end
|
|
51
|
+
unless associations.empty?
|
|
52
|
+
scope.joins! scope.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
|
|
55
53
|
end
|
|
54
|
+
end
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
arel = scope.arel(alias_tracker.aliases)
|
|
57
|
+
nodes = arel.constraints.first
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
end
|
|
59
|
+
if nodes.is_a?(Arel::Nodes::And)
|
|
60
|
+
others = nodes.children.extract! do |node|
|
|
61
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
|
64
62
|
end
|
|
63
|
+
end
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
joins << join_type.new(table, Arel::Nodes::On.new(nodes))
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# The current table in this iteration becomes the foreign table in the next
|
|
74
|
-
foreign_table, foreign_klass = table, klass
|
|
67
|
+
if others && !others.empty?
|
|
68
|
+
joins.concat arel.join_sources
|
|
69
|
+
append_constraints(joins.last, others)
|
|
75
70
|
end
|
|
71
|
+
|
|
72
|
+
# The current table in this iteration becomes the foreign table in the next
|
|
73
|
+
foreign_table, foreign_klass = table, klass
|
|
76
74
|
end
|
|
77
75
|
|
|
78
76
|
joins
|
|
@@ -91,10 +89,10 @@ module ActiveRecord
|
|
|
91
89
|
end
|
|
92
90
|
|
|
93
91
|
private
|
|
94
|
-
def append_constraints(
|
|
92
|
+
def append_constraints(join, constraints)
|
|
95
93
|
if join.is_a?(Arel::Nodes::StringJoin)
|
|
96
94
|
join_string = Arel::Nodes::And.new(constraints.unshift join.left)
|
|
97
|
-
join.left =
|
|
95
|
+
join.left = join_string
|
|
98
96
|
else
|
|
99
97
|
right = join.right
|
|
100
98
|
right.expr = Arel::Nodes::And.new(constraints.unshift right.expr)
|
|
@@ -103,7 +103,7 @@ module ActiveRecord
|
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
def instantiate(result_set, strict_loading_value, &block)
|
|
106
|
-
primary_key = aliases.column_alias(join_root,
|
|
106
|
+
primary_key = Array(join_root.primary_key).map { |column| aliases.column_alias(join_root, column) }
|
|
107
107
|
|
|
108
108
|
seen = Hash.new { |i, parent|
|
|
109
109
|
i[parent] = Hash.new { |j, child_class|
|
|
@@ -141,7 +141,7 @@ module ActiveRecord
|
|
|
141
141
|
|
|
142
142
|
message_bus.instrument("instantiation.active_record", payload) do
|
|
143
143
|
result_set.each { |row_hash|
|
|
144
|
-
parent_key = primary_key ? row_hash
|
|
144
|
+
parent_key = primary_key.empty? ? row_hash : row_hash.values_at(*primary_key)
|
|
145
145
|
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, column_types, &block)
|
|
146
146
|
construct(parent, join_root, row_hash, seen, model_cache, strict_loading_value)
|
|
147
147
|
}
|
|
@@ -168,8 +168,7 @@ module ActiveRecord
|
|
|
168
168
|
def aliases
|
|
169
169
|
@aliases ||= Aliases.new join_root.each_with_index.map { |join_part, i|
|
|
170
170
|
column_names = if join_part == join_root && !join_root_alias
|
|
171
|
-
|
|
172
|
-
primary_key ? [primary_key] : []
|
|
171
|
+
Array(join_root.primary_key)
|
|
173
172
|
else
|
|
174
173
|
join_part.column_names
|
|
175
174
|
end
|
|
@@ -235,6 +234,8 @@ module ActiveRecord
|
|
|
235
234
|
raise EagerLoadPolymorphicError.new(reflection)
|
|
236
235
|
end
|
|
237
236
|
|
|
237
|
+
Deprecation.guard(reflection) { "referenced in query to join its table" }
|
|
238
|
+
|
|
238
239
|
JoinAssociation.new(reflection, build(right, reflection.klass))
|
|
239
240
|
end
|
|
240
241
|
end
|
|
@@ -169,7 +169,7 @@ module ActiveRecord
|
|
|
169
169
|
def owners_by_key
|
|
170
170
|
@owners_by_key ||= owners.each_with_object({}) do |owner, result|
|
|
171
171
|
key = derive_key(owner, owner_key_name)
|
|
172
|
-
(result[key] ||= []) << owner if key
|
|
172
|
+
(result[key] ||= []) << owner if key.is_a?(Array) ? key.all? : key
|
|
173
173
|
end
|
|
174
174
|
end
|
|
175
175
|
|
|
@@ -38,7 +38,13 @@ module ActiveRecord
|
|
|
38
38
|
attr_reader :loaders
|
|
39
39
|
|
|
40
40
|
def group_and_load_similar(loaders)
|
|
41
|
-
loaders.grep_v(ThroughAssociation)
|
|
41
|
+
non_through = loaders.grep_v(ThroughAssociation)
|
|
42
|
+
|
|
43
|
+
grouped = non_through.group_by do |loader|
|
|
44
|
+
[loader.loader_query, loader.klass]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
grouped.each do |(query, _klass), similar_loaders|
|
|
42
48
|
query.load_records_in_batch(similar_loaders)
|
|
43
49
|
end
|
|
44
50
|
end
|
|
@@ -118,6 +118,7 @@ module ActiveRecord
|
|
|
118
118
|
def loaders
|
|
119
119
|
@loaders ||=
|
|
120
120
|
grouped_records.flat_map do |reflection, reflection_records|
|
|
121
|
+
Deprecation.guard(reflection) { "referenced in query to preload records" }
|
|
121
122
|
preloaders_for_reflection(reflection, reflection_records)
|
|
122
123
|
end
|
|
123
124
|
end
|
|
@@ -39,6 +39,8 @@ module ActiveRecord
|
|
|
39
39
|
autoload :AssociationScope
|
|
40
40
|
autoload :DisableJoinsAssociationScope
|
|
41
41
|
autoload :AliasTracker
|
|
42
|
+
|
|
43
|
+
autoload :Deprecation
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
def self.eager_load!
|
|
@@ -79,7 +81,7 @@ module ActiveRecord
|
|
|
79
81
|
|
|
80
82
|
# Returns the specified association instance if it exists, +nil+ otherwise.
|
|
81
83
|
def association_instance_get(name)
|
|
82
|
-
@association_cache[name]
|
|
84
|
+
(@association_cache ||= {})[name]
|
|
83
85
|
end
|
|
84
86
|
|
|
85
87
|
# Set the specified association instance.
|
|
@@ -87,6 +89,14 @@ module ActiveRecord
|
|
|
87
89
|
@association_cache[name] = association
|
|
88
90
|
end
|
|
89
91
|
|
|
92
|
+
def deprecated_associations_api_guard(association, method_name)
|
|
93
|
+
Deprecation.guard(association.reflection) { "the method #{method_name} was invoked" }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def report_deprecated_association(reflection, context:)
|
|
97
|
+
Deprecation.report(reflection, context: context)
|
|
98
|
+
end
|
|
99
|
+
|
|
90
100
|
# = Active Record \Associations
|
|
91
101
|
#
|
|
92
102
|
# \Associations are a set of macro-like class methods for tying objects together through
|
|
@@ -1020,6 +1030,116 @@ module ActiveRecord
|
|
|
1020
1030
|
# associated records themselves, you can always do something along the lines of
|
|
1021
1031
|
# <tt>person.tasks.each(&:destroy)</tt>.
|
|
1022
1032
|
#
|
|
1033
|
+
# == Deprecated \Associations
|
|
1034
|
+
#
|
|
1035
|
+
# \Associations can be marked as deprecated by passing <tt>deprecated: true</tt>:
|
|
1036
|
+
#
|
|
1037
|
+
# has_many :posts, deprecated: true
|
|
1038
|
+
#
|
|
1039
|
+
# When a deprecated association is used, a warning is issued using the
|
|
1040
|
+
# Active Record logger, though more options are available via
|
|
1041
|
+
# configuration.
|
|
1042
|
+
#
|
|
1043
|
+
# The message includes some context that helps understand the deprecated
|
|
1044
|
+
# usage:
|
|
1045
|
+
#
|
|
1046
|
+
# The association Author#posts is deprecated, the method post_ids was invoked (...)
|
|
1047
|
+
# The association Author#posts is deprecated, referenced in query to preload records (...)
|
|
1048
|
+
#
|
|
1049
|
+
# The dots in the examples above would have the application-level spot
|
|
1050
|
+
# where usage occurred, to help locate what triggered the warning. That
|
|
1051
|
+
# location is computed using the Active Record backtrace cleaner.
|
|
1052
|
+
#
|
|
1053
|
+
# === What is considered to be usage?
|
|
1054
|
+
#
|
|
1055
|
+
# * Invocation of any association methods like +posts+, <tt>posts=</tt>,
|
|
1056
|
+
# etc.
|
|
1057
|
+
#
|
|
1058
|
+
# * If the association accepts nested attributes, assignment to those
|
|
1059
|
+
# attributes.
|
|
1060
|
+
#
|
|
1061
|
+
# * If the association is a through association and some of its nested
|
|
1062
|
+
# associations are deprecated, you'll get warnings for them whenever the
|
|
1063
|
+
# top-level through is used. This is so regardless of whether the
|
|
1064
|
+
# through itself is deprecated.
|
|
1065
|
+
#
|
|
1066
|
+
# * Execution of queries that refer to the association. Think execution of
|
|
1067
|
+
# <tt>eager_load(:posts)</tt>, <tt>joins(author: :posts)</tt>, etc.
|
|
1068
|
+
#
|
|
1069
|
+
# * If the association has a +:dependent+ option, destroying the
|
|
1070
|
+
# associated record issues warnings (because that has a side-effect that
|
|
1071
|
+
# would not happen if the association was removed).
|
|
1072
|
+
#
|
|
1073
|
+
# * If the association has a +:touch+ option, saving or destroying the
|
|
1074
|
+
# record issues a warning (because that has a side-effect that would not
|
|
1075
|
+
# happen if the association was removed).
|
|
1076
|
+
#
|
|
1077
|
+
# === Things that do NOT issue warnings
|
|
1078
|
+
#
|
|
1079
|
+
# The rationale behind most of the following edge cases is that Active
|
|
1080
|
+
# Record accesses associations lazily, when used. Before that, the
|
|
1081
|
+
# reference to the association is basically just a Ruby symbol.
|
|
1082
|
+
#
|
|
1083
|
+
# * If +posts+ is deprecated, <tt>has_many :comments, through: :posts</tt>
|
|
1084
|
+
# does not warn. Usage of the +comments+ association reports usage of
|
|
1085
|
+
# +posts+, as we explained above, but the definition of the +has_many+
|
|
1086
|
+
# itself does not.
|
|
1087
|
+
#
|
|
1088
|
+
# * Similarly, <tt>accepts_nested_attributes_for :posts</tt> does not
|
|
1089
|
+
# warn. Assignment to the posts attributes warns, as explained above,
|
|
1090
|
+
# but the +accepts_nested_attributes_for+ call itself does not.
|
|
1091
|
+
#
|
|
1092
|
+
# * Same if an association declares to be inverse of a deprecated one, the
|
|
1093
|
+
# macro itself does not warn.
|
|
1094
|
+
#
|
|
1095
|
+
# * In the same line, the declaration <tt>validates_associated :posts</tt>
|
|
1096
|
+
# does not warn by itself, though access is reported when the validation
|
|
1097
|
+
# runs.
|
|
1098
|
+
#
|
|
1099
|
+
# * Relation query methods like <tt>Author.includes(:posts)</tt> do not
|
|
1100
|
+
# warn by themselves. At that point, that is a relation that internally
|
|
1101
|
+
# stores a symbol for later use. As explained in the previous section,
|
|
1102
|
+
# you get a warning when/if the query is executed.
|
|
1103
|
+
#
|
|
1104
|
+
# * Access to the reflection object of the association as in
|
|
1105
|
+
# <tt>Author.reflect_on_association(:posts)</tt> or
|
|
1106
|
+
# <tt>Author.reflect_on_all_associations</tt> does not warn.
|
|
1107
|
+
#
|
|
1108
|
+
# === Configuration
|
|
1109
|
+
#
|
|
1110
|
+
# Reporting deprecated usage can be configured:
|
|
1111
|
+
#
|
|
1112
|
+
# config.active_record.deprecated_associations_options = { ... }
|
|
1113
|
+
#
|
|
1114
|
+
# If present, this has to be a hash with keys +:mode+ and/or +:backtrace+.
|
|
1115
|
+
#
|
|
1116
|
+
# ==== Mode
|
|
1117
|
+
#
|
|
1118
|
+
# * In +:warn+ mode, usage issues a warning that includes the
|
|
1119
|
+
# application-level place where the access happened, if any. This is the
|
|
1120
|
+
# default mode.
|
|
1121
|
+
#
|
|
1122
|
+
# * In +:raise+ mode, usage raises an
|
|
1123
|
+
# ActiveRecord::DeprecatedAssociationError with a similar message and a
|
|
1124
|
+
# clean backtrace in the exception object.
|
|
1125
|
+
#
|
|
1126
|
+
# * In +:notify+ mode, a <tt>deprecated_association.active_record</tt>
|
|
1127
|
+
# Active Support notification is published. The event payload has the
|
|
1128
|
+
# association reflection (+:reflection+), the application-level location
|
|
1129
|
+
# (+:location+) where the access happened (a Thread::Backtrace::Location
|
|
1130
|
+
# object, or +nil+), and a deprecation message (+:message+).
|
|
1131
|
+
#
|
|
1132
|
+
# ==== Backtrace
|
|
1133
|
+
#
|
|
1134
|
+
# If +:backtrace+ is true, warnings include a clean backtrace in the message
|
|
1135
|
+
# and notifications have a +:backtrace+ key in the payload with an array
|
|
1136
|
+
# of clean Thread::Backtrace::Location objects. Exceptions always get a
|
|
1137
|
+
# clean stack trace set.
|
|
1138
|
+
#
|
|
1139
|
+
# Clean backtraces are computed using the Active Record backtrace cleaner.
|
|
1140
|
+
# In Rails applications, that is by the default the same as
|
|
1141
|
+
# <tt>Rails.backtrace_cleaner</tt>.
|
|
1142
|
+
#
|
|
1023
1143
|
# == Type safety with ActiveRecord::AssociationTypeMismatch
|
|
1024
1144
|
#
|
|
1025
1145
|
# If you attempt to assign an object to an association that doesn't match the inferred
|
|
@@ -1208,8 +1328,10 @@ module ActiveRecord
|
|
|
1208
1328
|
# [+:as+]
|
|
1209
1329
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1210
1330
|
# [+:through+]
|
|
1211
|
-
# Specifies an association through which to perform the query.
|
|
1212
|
-
#
|
|
1331
|
+
# Specifies an association through which to perform the query.
|
|
1332
|
+
#
|
|
1333
|
+
# This can be any other type of association, including other <tt>:through</tt> associations,
|
|
1334
|
+
# but it cannot be a polymorphic association. Options for <tt>:class_name</tt>,
|
|
1213
1335
|
# <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
|
|
1214
1336
|
# source reflection.
|
|
1215
1337
|
#
|
|
@@ -1285,6 +1407,9 @@ module ActiveRecord
|
|
|
1285
1407
|
# Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>before an object is removed</b> from the association collection.
|
|
1286
1408
|
# [:after_remove]
|
|
1287
1409
|
# Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>after an object is removed</b> from the association collection.
|
|
1410
|
+
# [+:deprecated+]
|
|
1411
|
+
# If true, marks the association as deprecated. Usage of deprecated associations is reported.
|
|
1412
|
+
# Please, check the class documentation above for details.
|
|
1288
1413
|
#
|
|
1289
1414
|
# Option examples:
|
|
1290
1415
|
# has_many :comments, -> { order("posted_on") }
|
|
@@ -1301,7 +1426,7 @@ module ActiveRecord
|
|
|
1301
1426
|
# has_many :comments, index_errors: :nested_attributes_order
|
|
1302
1427
|
def has_many(name, scope = nil, **options, &extension)
|
|
1303
1428
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
|
1304
|
-
Reflection.add_reflection
|
|
1429
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1305
1430
|
end
|
|
1306
1431
|
|
|
1307
1432
|
# Specifies a one-to-one association with another class. This method
|
|
@@ -1411,10 +1536,12 @@ module ActiveRecord
|
|
|
1411
1536
|
# [+:as+]
|
|
1412
1537
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1413
1538
|
# [+:through+]
|
|
1414
|
-
# Specifies
|
|
1415
|
-
#
|
|
1416
|
-
#
|
|
1417
|
-
#
|
|
1539
|
+
# Specifies an association through which to perform the query.
|
|
1540
|
+
#
|
|
1541
|
+
# The through association must be a +has_one+, <tt>has_one :through</tt>, or non-polymorphic +belongs_to+.
|
|
1542
|
+
# That is, a non-polymorphic singular association. Options for <tt>:class_name</tt>, <tt>:primary_key</tt>,
|
|
1543
|
+
# and <tt>:foreign_key</tt> are ignored, as the association uses the source reflection. You can only
|
|
1544
|
+
# use a <tt>:through</tt> query through a #has_one or #belongs_to association on the join model.
|
|
1418
1545
|
#
|
|
1419
1546
|
# If the association on the join model is a #belongs_to, the collection can be modified
|
|
1420
1547
|
# and the records on the <tt>:through</tt> model will be automatically created and removed
|
|
@@ -1480,12 +1607,15 @@ module ActiveRecord
|
|
|
1480
1607
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1481
1608
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1482
1609
|
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
|
1610
|
+
# [+:deprecated+]
|
|
1611
|
+
# If true, marks the association as deprecated. Usage of deprecated associations is reported.
|
|
1612
|
+
# Please, check the class documentation above for details.
|
|
1483
1613
|
#
|
|
1484
1614
|
# Option examples:
|
|
1485
1615
|
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
|
1486
1616
|
# has_one :credit_card, dependent: :nullify # updates the associated records foreign
|
|
1487
1617
|
# # key value to NULL rather than destroying it
|
|
1488
|
-
# has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
|
|
1618
|
+
# has_one :last_comment, -> { order('posted_on desc') }, class_name: "Comment"
|
|
1489
1619
|
# has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
|
|
1490
1620
|
# has_one :attachment, as: :attachable
|
|
1491
1621
|
# has_one :boss, -> { readonly }
|
|
@@ -1497,7 +1627,7 @@ module ActiveRecord
|
|
|
1497
1627
|
# has_one :employment_record_book, query_constraints: [:organization_id, :employee_id]
|
|
1498
1628
|
def has_one(name, scope = nil, **options)
|
|
1499
1629
|
reflection = Builder::HasOne.build(self, name, scope, options)
|
|
1500
|
-
Reflection.add_reflection
|
|
1630
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1501
1631
|
end
|
|
1502
1632
|
|
|
1503
1633
|
# Specifies a one-to-one association with another class. This method
|
|
@@ -1576,7 +1706,9 @@ module ActiveRecord
|
|
|
1576
1706
|
# [+:class_name+]
|
|
1577
1707
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1578
1708
|
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
|
|
1579
|
-
# if the real class name is Person, you'll have to specify it with this option.
|
|
1709
|
+
# if the real class name is Person, you'll have to specify it with this option. +:class_name+
|
|
1710
|
+
# is not supported in polymorphic associations, since in that case the class name of the
|
|
1711
|
+
# associated record is stored in the type column.
|
|
1580
1712
|
# [+:foreign_key+]
|
|
1581
1713
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
|
1582
1714
|
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
|
|
@@ -1670,6 +1802,9 @@ module ActiveRecord
|
|
|
1670
1802
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1671
1803
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1672
1804
|
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
|
1805
|
+
# [+:deprecated+]
|
|
1806
|
+
# If true, marks the association as deprecated. Usage of deprecated associations is reported.
|
|
1807
|
+
# Please, check the class documentation above for details.
|
|
1673
1808
|
#
|
|
1674
1809
|
# Option examples:
|
|
1675
1810
|
# belongs_to :firm, foreign_key: "client_of"
|
|
@@ -1688,7 +1823,7 @@ module ActiveRecord
|
|
|
1688
1823
|
# belongs_to :note, query_constraints: [:organization_id, :note_id]
|
|
1689
1824
|
def belongs_to(name, scope = nil, **options)
|
|
1690
1825
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
|
1691
|
-
Reflection.add_reflection
|
|
1826
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1692
1827
|
end
|
|
1693
1828
|
|
|
1694
1829
|
# Specifies a many-to-many relationship with another class. This associates two classes via an
|
|
@@ -1708,7 +1843,7 @@ module ActiveRecord
|
|
|
1708
1843
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
|
1709
1844
|
# join table with a migration such as this:
|
|
1710
1845
|
#
|
|
1711
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[8.
|
|
1846
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[8.1]
|
|
1712
1847
|
# def change
|
|
1713
1848
|
# create_join_table :developers, :projects
|
|
1714
1849
|
# end
|
|
@@ -1859,6 +1994,9 @@ module ActiveRecord
|
|
|
1859
1994
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
|
1860
1995
|
# [+:strict_loading+]
|
|
1861
1996
|
# Enforces strict loading every time an associated record is loaded through this association.
|
|
1997
|
+
# [+:deprecated+]
|
|
1998
|
+
# If true, marks the association as deprecated. Usage of deprecated associations is reported.
|
|
1999
|
+
# Please, check the class documentation above for details.
|
|
1862
2000
|
#
|
|
1863
2001
|
# Option examples:
|
|
1864
2002
|
# has_and_belongs_to_many :projects
|
|
@@ -1870,17 +2008,17 @@ module ActiveRecord
|
|
|
1870
2008
|
def has_and_belongs_to_many(name, scope = nil, **options, &extension)
|
|
1871
2009
|
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
|
1872
2010
|
|
|
1873
|
-
builder = Builder::HasAndBelongsToMany.new
|
|
2011
|
+
builder = Builder::HasAndBelongsToMany.new(name, self, options)
|
|
1874
2012
|
|
|
1875
2013
|
join_model = builder.through_model
|
|
1876
2014
|
|
|
1877
|
-
const_set
|
|
1878
|
-
private_constant
|
|
2015
|
+
const_set(join_model.name, join_model)
|
|
2016
|
+
private_constant(join_model.name)
|
|
1879
2017
|
|
|
1880
|
-
middle_reflection = builder.middle_reflection
|
|
2018
|
+
middle_reflection = builder.middle_reflection(join_model)
|
|
1881
2019
|
|
|
1882
|
-
Builder::HasMany.define_callbacks
|
|
1883
|
-
Reflection.add_reflection
|
|
2020
|
+
Builder::HasMany.define_callbacks(self, middle_reflection)
|
|
2021
|
+
Reflection.add_reflection(self, middle_reflection.name, middle_reflection)
|
|
1884
2022
|
middle_reflection.parent_reflection = habtm_reflection
|
|
1885
2023
|
|
|
1886
2024
|
include Module.new {
|
|
@@ -1897,8 +2035,8 @@ module ActiveRecord
|
|
|
1897
2035
|
hm_options[:through] = middle_reflection.name
|
|
1898
2036
|
hm_options[:source] = join_model.right_reflection.name
|
|
1899
2037
|
|
|
1900
|
-
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
|
|
1901
|
-
hm_options[k] = options[k] if options.key?
|
|
2038
|
+
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading, :deprecated].each do |k|
|
|
2039
|
+
hm_options[k] = options[k] if options.key?(k)
|
|
1902
2040
|
end
|
|
1903
2041
|
|
|
1904
2042
|
has_many name, scope, **hm_options, &extension
|
|
@@ -129,12 +129,13 @@ module ActiveRecord
|
|
|
129
129
|
# Project.primary_key # => "foo_id"
|
|
130
130
|
def primary_key=(value)
|
|
131
131
|
@primary_key = if value.is_a?(Array)
|
|
132
|
-
@composite_primary_key = true
|
|
133
132
|
include CompositePrimaryKey
|
|
134
133
|
@primary_key = value.map { |v| -v.to_s }.freeze
|
|
135
134
|
elsif value
|
|
136
135
|
-value.to_s
|
|
137
136
|
end
|
|
137
|
+
|
|
138
|
+
@composite_primary_key = value.is_a?(Array)
|
|
138
139
|
@attributes_builder = nil
|
|
139
140
|
end
|
|
140
141
|
|
|
@@ -3,6 +3,38 @@
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
module AttributeMethods
|
|
5
5
|
# = Active Record Attribute Methods \Query
|
|
6
|
+
#
|
|
7
|
+
# Adds query methods for attributes that return either +true+ or +false+
|
|
8
|
+
# depending on the attribute type and value.
|
|
9
|
+
#
|
|
10
|
+
# For Boolean attributes this will return +true+ if the value is present
|
|
11
|
+
# and return +false+ otherwise:
|
|
12
|
+
#
|
|
13
|
+
# class Product < ActiveRecord::Base
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# product = Product.new(archived: false)
|
|
17
|
+
# product.archived? # => false
|
|
18
|
+
# product.archived = true
|
|
19
|
+
# product.archived? # => true
|
|
20
|
+
#
|
|
21
|
+
# For Numeric attributes this will return +true+ if the value is a non-zero
|
|
22
|
+
# number and return +false+ otherwise:
|
|
23
|
+
#
|
|
24
|
+
# product.inventory_count = 0
|
|
25
|
+
# product.inventory_count? # => false
|
|
26
|
+
# product.inventory_count = 1
|
|
27
|
+
# product.inventory_count? # => true
|
|
28
|
+
#
|
|
29
|
+
# For other attributes it will return +true+ if the value is present
|
|
30
|
+
# and return +false+ otherwise:
|
|
31
|
+
#
|
|
32
|
+
# product.name = nil
|
|
33
|
+
# product.name? # => false
|
|
34
|
+
# product.name = " "
|
|
35
|
+
# product.name? # => false
|
|
36
|
+
# product.name = "Orange"
|
|
37
|
+
# product.name? # => true
|
|
6
38
|
module Query
|
|
7
39
|
extend ActiveSupport::Concern
|
|
8
40
|
|
|
@@ -10,6 +42,8 @@ module ActiveRecord
|
|
|
10
42
|
attribute_method_suffix "?", parameters: false
|
|
11
43
|
end
|
|
12
44
|
|
|
45
|
+
# Returns +true+ or +false+ for the attribute identified by +attr_name+,
|
|
46
|
+
# depending on the attribute type and value.
|
|
13
47
|
def query_attribute(attr_name)
|
|
14
48
|
value = self.public_send(attr_name)
|
|
15
49
|
|
|
@@ -51,6 +51,16 @@ module ActiveRecord
|
|
|
51
51
|
# ActiveRecord::SerializationTypeMismatch error.
|
|
52
52
|
# * If the column is +NULL+ or starting from a new record, the default value
|
|
53
53
|
# will set to +type.new+
|
|
54
|
+
# * +comparable+ - Specify whether the deserialized object is safely comparable
|
|
55
|
+
# for the purpose of detecting changes. Defaults to +false+
|
|
56
|
+
# When set to +false+ the old and new values will be compared by their serialized
|
|
57
|
+
# representation (e.g. JSON or YAML), which can sometimes cause two objects that are
|
|
58
|
+
# semantically equal to be considered different.
|
|
59
|
+
# For instance two hashes with the same keys and values but a different order have a
|
|
60
|
+
# different serialized representation, but are semantically equal once deserialized.
|
|
61
|
+
# If set to +true+ the comparison will be done on the deserialized object.
|
|
62
|
+
# This options should only be enabled if the +type+ is known to have
|
|
63
|
+
# a proper <tt>==</tt> method that deeply compare the objects.
|
|
54
64
|
# * +yaml+ - Optional. Yaml specific options. The allowed config is:
|
|
55
65
|
# * +:permitted_classes+ - +Array+ with the permitted classes.
|
|
56
66
|
# * +:unsafe_load+ - Unsafely load YAML blobs, allow YAML to load any class.
|
|
@@ -130,7 +140,7 @@ module ActiveRecord
|
|
|
130
140
|
# silently cast unsupported types to +String+:
|
|
131
141
|
#
|
|
132
142
|
# >> JSON.parse(JSON.dump(Struct.new(:foo)))
|
|
133
|
-
# => "#<Class:0x000000013090b4c0>"
|
|
143
|
+
# # => "#<Class:0x000000013090b4c0>"
|
|
134
144
|
#
|
|
135
145
|
# ==== Examples
|
|
136
146
|
#
|
|
@@ -180,7 +190,7 @@ module ActiveRecord
|
|
|
180
190
|
# serialize :preferences, coder: Rot13JSON
|
|
181
191
|
# end
|
|
182
192
|
#
|
|
183
|
-
def serialize(attr_name, coder: nil, type: Object, yaml: {}, **options)
|
|
193
|
+
def serialize(attr_name, coder: nil, type: Object, comparable: false, yaml: {}, **options)
|
|
184
194
|
coder ||= default_column_serializer
|
|
185
195
|
unless coder
|
|
186
196
|
raise ArgumentError, <<~MSG.squish
|
|
@@ -195,12 +205,12 @@ module ActiveRecord
|
|
|
195
205
|
attribute(attr_name, **options)
|
|
196
206
|
|
|
197
207
|
decorate_attributes([attr_name]) do |attr_name, cast_type|
|
|
198
|
-
if type_incompatible_with_serialize?(cast_type,
|
|
208
|
+
if type_incompatible_with_serialize?(cast_type, column_serializer, type)
|
|
199
209
|
raise ColumnNotSerializableError.new(attr_name, cast_type)
|
|
200
210
|
end
|
|
201
211
|
|
|
202
212
|
cast_type = cast_type.subtype if Type::Serialized === cast_type
|
|
203
|
-
Type::Serialized.new(cast_type, column_serializer)
|
|
213
|
+
Type::Serialized.new(cast_type, column_serializer, comparable: comparable)
|
|
204
214
|
end
|
|
205
215
|
end
|
|
206
216
|
|
|
@@ -209,7 +219,10 @@ module ActiveRecord
|
|
|
209
219
|
# When ::JSON is used, force it to go through the Active Support JSON encoder
|
|
210
220
|
# to ensure special objects (e.g. Active Record models) are dumped correctly
|
|
211
221
|
# using the #as_json hook.
|
|
212
|
-
|
|
222
|
+
|
|
223
|
+
if coder == ::JSON || coder == Coders::JSON
|
|
224
|
+
coder = Coders::JSON.new
|
|
225
|
+
end
|
|
213
226
|
|
|
214
227
|
if coder == ::YAML || coder == Coders::YAMLColumn
|
|
215
228
|
Coders::YAMLColumn.new(attr_name, type, **(yaml || {}))
|
|
@@ -223,7 +236,7 @@ module ActiveRecord
|
|
|
223
236
|
end
|
|
224
237
|
|
|
225
238
|
def type_incompatible_with_serialize?(cast_type, coder, type)
|
|
226
|
-
cast_type.is_a?(ActiveRecord::Type::Json) &&
|
|
239
|
+
cast_type.is_a?(ActiveRecord::Type::Json) && Coders::JSON === coder ||
|
|
227
240
|
cast_type.respond_to?(:type_cast_array, true) && type == ::Array
|
|
228
241
|
end
|
|
229
242
|
end
|
|
@@ -21,7 +21,11 @@ module ActiveRecord
|
|
|
21
21
|
set_time_zone_without_conversion(super)
|
|
22
22
|
elsif value.respond_to?(:in_time_zone)
|
|
23
23
|
begin
|
|
24
|
-
super(user_input_in_time_zone(value)) || super
|
|
24
|
+
result = super(user_input_in_time_zone(value)) || super
|
|
25
|
+
if result && type == :time
|
|
26
|
+
result = result.change(year: 2000, month: 1, day: 1)
|
|
27
|
+
end
|
|
28
|
+
result
|
|
25
29
|
rescue ArgumentError
|
|
26
30
|
nil
|
|
27
31
|
end
|
|
@@ -41,7 +45,11 @@ module ActiveRecord
|
|
|
41
45
|
return if value.nil?
|
|
42
46
|
|
|
43
47
|
if value.acts_like?(:time)
|
|
44
|
-
value.in_time_zone
|
|
48
|
+
converted = value.in_time_zone
|
|
49
|
+
if type == :time && converted
|
|
50
|
+
converted = converted.change(year: 2000, month: 1, day: 1)
|
|
51
|
+
end
|
|
52
|
+
converted
|
|
45
53
|
elsif value.respond_to?(:infinite?) && value.infinite?
|
|
46
54
|
value
|
|
47
55
|
else
|