activerecord 7.2.2.1 → 8.1.2
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 +564 -753
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -11
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- 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 +10 -8
- data/lib/active_record/associations/collection_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/has_many_through_association.rb +3 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +4 -2
- data/lib/active_record/associations/preloader/association.rb +2 -2
- 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/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +192 -24
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/primary_key.rb +4 -8
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +17 -4
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -14
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +91 -39
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +35 -28
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +458 -117
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +136 -74
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +44 -11
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -25
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +122 -29
- data/lib/active_record/connection_adapters/abstract/transaction.rb +40 -8
- data/lib/active_record/connection_adapters/abstract_adapter.rb +175 -87
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +77 -58
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -9
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +73 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +89 -94
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +10 -11
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -45
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- 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 +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +28 -45
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +140 -64
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +83 -105
- data/lib/active_record/connection_adapters/schema_cache.rb +3 -5
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +90 -98
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +27 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +13 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +112 -42
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +38 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +2 -19
- data/lib/active_record/connection_adapters.rb +1 -56
- data/lib/active_record/connection_handling.rb +37 -10
- data/lib/active_record/core.rb +61 -25
- data/lib/active_record/counter_cache.rb +34 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +9 -1
- data/lib/active_record/database_configurations/hash_config.rb +67 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +9 -9
- data/lib/active_record/encryption/encrypted_attribute_type.rb +12 -3
- data/lib/active_record/encryption/encryptor.rb +49 -28
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +9 -2
- data/lib/active_record/enum.rb +46 -42
- data/lib/active_record/errors.rb +36 -12
- 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 +73 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -4
- data/lib/active_record/future_result.rb +13 -9
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- data/lib/active_record/locking/optimistic.rb +8 -1
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -13
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +44 -11
- data/lib/active_record/migration/compatibility.rb +37 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +50 -43
- data/lib/active_record/model_schema.rb +38 -13
- data/lib/active_record/nested_attributes.rb +6 -6
- data/lib/active_record/persistence.rb +162 -133
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +104 -52
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +12 -12
- data/lib/active_record/railtie.rb +37 -32
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +26 -37
- 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 +53 -21
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +147 -73
- data/lib/active_record/relation/calculations.rb +80 -63
- data/lib/active_record/relation/delegation.rb +25 -15
- data/lib/active_record/relation/finder_methods.rb +54 -37
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +22 -7
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +156 -95
- data/lib/active_record/relation/spawn_methods.rb +7 -7
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +122 -80
- data/lib/active_record/result.rb +109 -24
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +9 -6
- data/lib/active_record/schema_dumper.rb +47 -22
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +47 -18
- data/lib/active_record/statement_cache.rb +24 -20
- data/lib/active_record/store.rb +51 -22
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +6 -23
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +85 -85
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +39 -2
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +39 -16
- 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 +15 -2
- data/lib/active_record/type/serialized.rb +11 -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/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +85 -50
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/collectors/bind.rb +2 -2
- 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/select_manager.rb +13 -4
- data/lib/arel/table.rb +3 -7
- 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 +6 -22
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +17 -17
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
- data/lib/active_record/relation/record_fetch_warning.rb +0 -52
|
@@ -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
|
}
|
|
@@ -235,6 +235,8 @@ module ActiveRecord
|
|
|
235
235
|
raise EagerLoadPolymorphicError.new(reflection)
|
|
236
236
|
end
|
|
237
237
|
|
|
238
|
+
Deprecation.guard(reflection) { "referenced in query to join its table" }
|
|
239
|
+
|
|
238
240
|
JoinAssociation.new(reflection, build(right, reflection.klass))
|
|
239
241
|
end
|
|
240
242
|
end
|
|
@@ -17,12 +17,12 @@ module ActiveRecord
|
|
|
17
17
|
def eql?(other)
|
|
18
18
|
association_key_name == other.association_key_name &&
|
|
19
19
|
scope.table_name == other.scope.table_name &&
|
|
20
|
-
scope.connection_specification_name == other.scope.connection_specification_name &&
|
|
20
|
+
scope.model.connection_specification_name == other.scope.model.connection_specification_name &&
|
|
21
21
|
scope.values_for_queries == other.scope.values_for_queries
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def hash
|
|
25
|
-
[association_key_name, scope.table_name, scope.connection_specification_name, scope.values_for_queries].hash
|
|
25
|
+
[association_key_name, scope.model.table_name, scope.model.connection_specification_name, scope.values_for_queries].hash
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def records_for(loaders)
|
|
@@ -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
|
|
@@ -18,6 +18,7 @@ module ActiveRecord
|
|
|
18
18
|
def reset
|
|
19
19
|
super
|
|
20
20
|
@target = nil
|
|
21
|
+
@future_target = nil
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
# Implements the writer method, e.g. foo.bar= for Foo.belongs_to :bar
|
|
@@ -43,11 +44,15 @@ module ActiveRecord
|
|
|
43
44
|
super.except!(*Array(klass.primary_key))
|
|
44
45
|
end
|
|
45
46
|
|
|
46
|
-
def find_target
|
|
47
|
+
def find_target(async: false)
|
|
47
48
|
if disable_joins
|
|
48
|
-
|
|
49
|
+
if async
|
|
50
|
+
scope.load_async.then(&:first)
|
|
51
|
+
else
|
|
52
|
+
scope.first
|
|
53
|
+
end
|
|
49
54
|
else
|
|
50
|
-
super.first
|
|
55
|
+
super.then(&:first)
|
|
51
56
|
end
|
|
52
57
|
end
|
|
53
58
|
|
|
@@ -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
|
|
@@ -379,21 +389,43 @@ module ActiveRecord
|
|
|
379
389
|
# after_add: :congratulate_client,
|
|
380
390
|
# after_remove: :log_after_remove
|
|
381
391
|
#
|
|
382
|
-
# def congratulate_client(
|
|
392
|
+
# def congratulate_client(client)
|
|
383
393
|
# # ...
|
|
384
394
|
# end
|
|
385
395
|
#
|
|
386
|
-
# def log_after_remove(
|
|
396
|
+
# def log_after_remove(client)
|
|
387
397
|
# # ...
|
|
388
398
|
# end
|
|
389
399
|
# end
|
|
390
400
|
#
|
|
401
|
+
# Callbacks can be defined in three ways:
|
|
402
|
+
#
|
|
403
|
+
# 1. A symbol that references a method defined on the class with the
|
|
404
|
+
# associated collection. For example, <tt>after_add: :congratulate_client</tt>
|
|
405
|
+
# invokes <tt>Firm#congratulate_client(client)</tt>.
|
|
406
|
+
# 2. A callable with a signature that accepts both the record with the
|
|
407
|
+
# associated collection and the record being added or removed. For
|
|
408
|
+
# example, <tt>after_add: ->(firm, client) { ... }</tt>.
|
|
409
|
+
# 3. An object that responds to the callback name. For example, passing
|
|
410
|
+
# <tt>after_add: CallbackObject.new</tt> invokes <tt>CallbackObject#after_add(firm,
|
|
411
|
+
# client)</tt>.
|
|
412
|
+
#
|
|
391
413
|
# It's possible to stack callbacks by passing them as an array. Example:
|
|
392
414
|
#
|
|
415
|
+
# class CallbackObject
|
|
416
|
+
# def after_add(firm, client)
|
|
417
|
+
# firm.log << "after_adding #{client.id}"
|
|
418
|
+
# end
|
|
419
|
+
# end
|
|
420
|
+
#
|
|
393
421
|
# class Firm < ActiveRecord::Base
|
|
394
422
|
# has_many :clients,
|
|
395
423
|
# dependent: :destroy,
|
|
396
|
-
# after_add: [
|
|
424
|
+
# after_add: [
|
|
425
|
+
# :congratulate_client,
|
|
426
|
+
# -> (firm, client) { firm.log << "after_adding #{client.id}" },
|
|
427
|
+
# CallbackObject.new
|
|
428
|
+
# ],
|
|
397
429
|
# after_remove: :log_after_remove
|
|
398
430
|
# end
|
|
399
431
|
#
|
|
@@ -998,6 +1030,116 @@ module ActiveRecord
|
|
|
998
1030
|
# associated records themselves, you can always do something along the lines of
|
|
999
1031
|
# <tt>person.tasks.each(&:destroy)</tt>.
|
|
1000
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
|
+
#
|
|
1001
1143
|
# == Type safety with ActiveRecord::AssociationTypeMismatch
|
|
1002
1144
|
#
|
|
1003
1145
|
# If you attempt to assign an object to an association that doesn't match the inferred
|
|
@@ -1186,8 +1328,10 @@ module ActiveRecord
|
|
|
1186
1328
|
# [+:as+]
|
|
1187
1329
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1188
1330
|
# [+:through+]
|
|
1189
|
-
# Specifies an association through which to perform the query.
|
|
1190
|
-
#
|
|
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>,
|
|
1191
1335
|
# <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
|
|
1192
1336
|
# source reflection.
|
|
1193
1337
|
#
|
|
@@ -1255,6 +1399,17 @@ module ActiveRecord
|
|
|
1255
1399
|
# persisted new records placed at the end.
|
|
1256
1400
|
# When set to +:nested_attributes_order+, the index is based on the record order received by
|
|
1257
1401
|
# nested attributes setter, when accepts_nested_attributes_for is used.
|
|
1402
|
+
# [:before_add]
|
|
1403
|
+
# Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>before an object is added</b> to the association collection.
|
|
1404
|
+
# [:after_add]
|
|
1405
|
+
# Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>after an object is added</b> to the association collection.
|
|
1406
|
+
# [:before_remove]
|
|
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.
|
|
1408
|
+
# [:after_remove]
|
|
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.
|
|
1258
1413
|
#
|
|
1259
1414
|
# Option examples:
|
|
1260
1415
|
# has_many :comments, -> { order("posted_on") }
|
|
@@ -1271,7 +1426,7 @@ module ActiveRecord
|
|
|
1271
1426
|
# has_many :comments, index_errors: :nested_attributes_order
|
|
1272
1427
|
def has_many(name, scope = nil, **options, &extension)
|
|
1273
1428
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
|
1274
|
-
Reflection.add_reflection
|
|
1429
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1275
1430
|
end
|
|
1276
1431
|
|
|
1277
1432
|
# Specifies a one-to-one association with another class. This method
|
|
@@ -1381,10 +1536,12 @@ module ActiveRecord
|
|
|
1381
1536
|
# [+:as+]
|
|
1382
1537
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1383
1538
|
# [+:through+]
|
|
1384
|
-
# Specifies
|
|
1385
|
-
#
|
|
1386
|
-
#
|
|
1387
|
-
#
|
|
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.
|
|
1388
1545
|
#
|
|
1389
1546
|
# If the association on the join model is a #belongs_to, the collection can be modified
|
|
1390
1547
|
# and the records on the <tt>:through</tt> model will be automatically created and removed
|
|
@@ -1450,12 +1607,15 @@ module ActiveRecord
|
|
|
1450
1607
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1451
1608
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1452
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.
|
|
1453
1613
|
#
|
|
1454
1614
|
# Option examples:
|
|
1455
1615
|
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
|
1456
1616
|
# has_one :credit_card, dependent: :nullify # updates the associated records foreign
|
|
1457
1617
|
# # key value to NULL rather than destroying it
|
|
1458
|
-
# has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
|
|
1618
|
+
# has_one :last_comment, -> { order('posted_on desc') }, class_name: "Comment"
|
|
1459
1619
|
# has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
|
|
1460
1620
|
# has_one :attachment, as: :attachable
|
|
1461
1621
|
# has_one :boss, -> { readonly }
|
|
@@ -1467,7 +1627,7 @@ module ActiveRecord
|
|
|
1467
1627
|
# has_one :employment_record_book, query_constraints: [:organization_id, :employee_id]
|
|
1468
1628
|
def has_one(name, scope = nil, **options)
|
|
1469
1629
|
reflection = Builder::HasOne.build(self, name, scope, options)
|
|
1470
|
-
Reflection.add_reflection
|
|
1630
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1471
1631
|
end
|
|
1472
1632
|
|
|
1473
1633
|
# Specifies a one-to-one association with another class. This method
|
|
@@ -1546,7 +1706,9 @@ module ActiveRecord
|
|
|
1546
1706
|
# [+:class_name+]
|
|
1547
1707
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1548
1708
|
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
|
|
1549
|
-
# 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.
|
|
1550
1712
|
# [+:foreign_key+]
|
|
1551
1713
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
|
1552
1714
|
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
|
|
@@ -1640,6 +1802,9 @@ module ActiveRecord
|
|
|
1640
1802
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1641
1803
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1642
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.
|
|
1643
1808
|
#
|
|
1644
1809
|
# Option examples:
|
|
1645
1810
|
# belongs_to :firm, foreign_key: "client_of"
|
|
@@ -1658,7 +1823,7 @@ module ActiveRecord
|
|
|
1658
1823
|
# belongs_to :note, query_constraints: [:organization_id, :note_id]
|
|
1659
1824
|
def belongs_to(name, scope = nil, **options)
|
|
1660
1825
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
|
1661
|
-
Reflection.add_reflection
|
|
1826
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1662
1827
|
end
|
|
1663
1828
|
|
|
1664
1829
|
# Specifies a many-to-many relationship with another class. This associates two classes via an
|
|
@@ -1678,7 +1843,7 @@ module ActiveRecord
|
|
|
1678
1843
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
|
1679
1844
|
# join table with a migration such as this:
|
|
1680
1845
|
#
|
|
1681
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[
|
|
1846
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[8.1]
|
|
1682
1847
|
# def change
|
|
1683
1848
|
# create_join_table :developers, :projects
|
|
1684
1849
|
# end
|
|
@@ -1829,6 +1994,9 @@ module ActiveRecord
|
|
|
1829
1994
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
|
1830
1995
|
# [+:strict_loading+]
|
|
1831
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.
|
|
1832
2000
|
#
|
|
1833
2001
|
# Option examples:
|
|
1834
2002
|
# has_and_belongs_to_many :projects
|
|
@@ -1840,17 +2008,17 @@ module ActiveRecord
|
|
|
1840
2008
|
def has_and_belongs_to_many(name, scope = nil, **options, &extension)
|
|
1841
2009
|
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
|
1842
2010
|
|
|
1843
|
-
builder = Builder::HasAndBelongsToMany.new
|
|
2011
|
+
builder = Builder::HasAndBelongsToMany.new(name, self, options)
|
|
1844
2012
|
|
|
1845
2013
|
join_model = builder.through_model
|
|
1846
2014
|
|
|
1847
|
-
const_set
|
|
1848
|
-
private_constant
|
|
2015
|
+
const_set(join_model.name, join_model)
|
|
2016
|
+
private_constant(join_model.name)
|
|
1849
2017
|
|
|
1850
|
-
middle_reflection = builder.middle_reflection
|
|
2018
|
+
middle_reflection = builder.middle_reflection(join_model)
|
|
1851
2019
|
|
|
1852
|
-
Builder::HasMany.define_callbacks
|
|
1853
|
-
Reflection.add_reflection
|
|
2020
|
+
Builder::HasMany.define_callbacks(self, middle_reflection)
|
|
2021
|
+
Reflection.add_reflection(self, middle_reflection.name, middle_reflection)
|
|
1854
2022
|
middle_reflection.parent_reflection = habtm_reflection
|
|
1855
2023
|
|
|
1856
2024
|
include Module.new {
|
|
@@ -1867,8 +2035,8 @@ module ActiveRecord
|
|
|
1867
2035
|
hm_options[:through] = middle_reflection.name
|
|
1868
2036
|
hm_options[:source] = join_model.right_reflection.name
|
|
1869
2037
|
|
|
1870
|
-
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
|
|
1871
|
-
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)
|
|
1872
2040
|
end
|
|
1873
2041
|
|
|
1874
2042
|
has_many name, scope, **hm_options, &extension
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "concurrent/atomic/atomic_boolean"
|
|
4
|
+
require "concurrent/atomic/read_write_lock"
|
|
5
|
+
|
|
3
6
|
module ActiveRecord
|
|
4
7
|
class AsynchronousQueriesTracker # :nodoc:
|
|
5
|
-
module NullSession # :nodoc:
|
|
6
|
-
class << self
|
|
7
|
-
def active?
|
|
8
|
-
true
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def finalize
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
8
|
class Session # :nodoc:
|
|
17
9
|
def initialize
|
|
18
|
-
@active = true
|
|
10
|
+
@active = Concurrent::AtomicBoolean.new(true)
|
|
11
|
+
@lock = Concurrent::ReadWriteLock.new
|
|
19
12
|
end
|
|
20
13
|
|
|
21
14
|
def active?
|
|
22
|
-
@active
|
|
15
|
+
@active.true?
|
|
23
16
|
end
|
|
24
17
|
|
|
25
|
-
def
|
|
26
|
-
@
|
|
18
|
+
def synchronize(&block)
|
|
19
|
+
@lock.with_read_lock(&block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def finalize(wait = false)
|
|
23
|
+
@active.make_false
|
|
24
|
+
if wait
|
|
25
|
+
# Wait until all thread with a read lock are done
|
|
26
|
+
@lock.with_write_lock { }
|
|
27
|
+
end
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
|
|
@@ -33,7 +34,7 @@ module ActiveRecord
|
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
def run
|
|
36
|
-
ActiveRecord::Base.asynchronous_queries_tracker.start_session
|
|
37
|
+
ActiveRecord::Base.asynchronous_queries_tracker.tap(&:start_session)
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
def complete(asynchronous_queries_tracker)
|
|
@@ -41,20 +42,23 @@ module ActiveRecord
|
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
|
|
44
|
-
attr_reader :current_session
|
|
45
|
-
|
|
46
45
|
def initialize
|
|
47
|
-
@
|
|
46
|
+
@stack = []
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def current_session
|
|
50
|
+
@stack.last or raise ActiveRecordError, "Can't perform asynchronous queries without a query session"
|
|
48
51
|
end
|
|
49
52
|
|
|
50
53
|
def start_session
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
session = Session.new
|
|
55
|
+
@stack << session
|
|
53
56
|
end
|
|
54
57
|
|
|
55
|
-
def finalize_session
|
|
56
|
-
@
|
|
57
|
-
|
|
58
|
+
def finalize_session(wait = false)
|
|
59
|
+
session = @stack.pop
|
|
60
|
+
session&.finalize(wait)
|
|
61
|
+
self
|
|
58
62
|
end
|
|
59
63
|
end
|
|
60
64
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
|
-
|
|
5
3
|
module ActiveRecord
|
|
6
4
|
module AttributeMethods
|
|
7
5
|
# = Active Record Attribute Methods Primary Key
|
|
@@ -89,10 +87,9 @@ module ActiveRecord
|
|
|
89
87
|
@composite_primary_key
|
|
90
88
|
end
|
|
91
89
|
|
|
92
|
-
# Returns a quoted version of the primary key name
|
|
93
|
-
# SQL statements.
|
|
90
|
+
# Returns a quoted version of the primary key name.
|
|
94
91
|
def quoted_primary_key
|
|
95
|
-
|
|
92
|
+
adapter_class.quote_column_name(primary_key)
|
|
96
93
|
end
|
|
97
94
|
|
|
98
95
|
def reset_primary_key # :nodoc:
|
|
@@ -132,13 +129,13 @@ module ActiveRecord
|
|
|
132
129
|
# Project.primary_key # => "foo_id"
|
|
133
130
|
def primary_key=(value)
|
|
134
131
|
@primary_key = if value.is_a?(Array)
|
|
135
|
-
@composite_primary_key = true
|
|
136
132
|
include CompositePrimaryKey
|
|
137
133
|
@primary_key = value.map { |v| -v.to_s }.freeze
|
|
138
134
|
elsif value
|
|
139
135
|
-value.to_s
|
|
140
136
|
end
|
|
141
|
-
|
|
137
|
+
|
|
138
|
+
@composite_primary_key = value.is_a?(Array)
|
|
142
139
|
@attributes_builder = nil
|
|
143
140
|
end
|
|
144
141
|
|
|
@@ -148,7 +145,6 @@ module ActiveRecord
|
|
|
148
145
|
base.class_eval do
|
|
149
146
|
@primary_key = PRIMARY_KEY_NOT_SET
|
|
150
147
|
@composite_primary_key = false
|
|
151
|
-
@quoted_primary_key = nil
|
|
152
148
|
@attributes_builder = nil
|
|
153
149
|
end
|
|
154
150
|
end
|