activerecord 7.1.5.1 → 8.0.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 +369 -2484
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +21 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +92 -295
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +63 -49
- data/lib/active_record/autosave_association.rb +92 -57
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
- data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
- data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
- data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +65 -0
- data/lib/active_record/connection_handling.rb +74 -37
- data/lib/active_record/core.rb +132 -51
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +23 -4
- data/lib/active_record/database_configurations/hash_config.rb +46 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +41 -17
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +7 -7
- data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
- data/lib/active_record/encryption/encryptor.rb +28 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +20 -16
- data/lib/active_record/errors.rb +54 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -33
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +19 -16
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/log_subscriber.rb +5 -32
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +33 -14
- data/lib/active_record/migration/compatibility.rb +8 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +104 -98
- data/lib/active_record/model_schema.rb +32 -70
- data/lib/active_record/nested_attributes.rb +15 -9
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +127 -451
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +104 -37
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +24 -12
- data/lib/active_record/railtie.rb +26 -68
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +43 -61
- data/lib/active_record/reflection.rb +112 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +138 -72
- data/lib/active_record/relation/calculations.rb +122 -82
- data/lib/active_record/relation/delegation.rb +30 -22
- data/lib/active_record/relation/finder_methods.rb +32 -18
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +16 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +317 -101
- data/lib/active_record/relation/spawn_methods.rb +3 -19
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +561 -119
- data/lib/active_record/result.rb +95 -46
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +31 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +53 -20
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/signed_id.rb +24 -4
- data/lib/active_record/statement_cache.rb +19 -19
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +2 -13
- data/lib/active_record/tasks/database_tasks.rb +87 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
- data/lib/active_record/test_fixtures.rb +98 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +72 -17
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +138 -57
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +5 -4
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -16
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -1,268 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
-
class AssociationNotFoundError < ConfigurationError # :nodoc:
|
5
|
-
attr_reader :record, :association_name
|
6
|
-
|
7
|
-
def initialize(record = nil, association_name = nil)
|
8
|
-
@record = record
|
9
|
-
@association_name = association_name
|
10
|
-
if record && association_name
|
11
|
-
super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
|
12
|
-
else
|
13
|
-
super("Association was not found.")
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
18
|
-
include DidYouMean::Correctable
|
19
|
-
|
20
|
-
def corrections
|
21
|
-
if record && association_name
|
22
|
-
@corrections ||= begin
|
23
|
-
maybe_these = record.class.reflections.keys
|
24
|
-
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(association_name)
|
25
|
-
end
|
26
|
-
else
|
27
|
-
[]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class InverseOfAssociationNotFoundError < ActiveRecordError # :nodoc:
|
34
|
-
attr_reader :reflection, :associated_class
|
35
|
-
|
36
|
-
def initialize(reflection = nil, associated_class = nil)
|
37
|
-
if reflection
|
38
|
-
@reflection = reflection
|
39
|
-
@associated_class = associated_class.nil? ? reflection.klass : associated_class
|
40
|
-
super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
|
41
|
-
else
|
42
|
-
super("Could not find the inverse association.")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
47
|
-
include DidYouMean::Correctable
|
48
|
-
|
49
|
-
def corrections
|
50
|
-
if reflection && associated_class
|
51
|
-
@corrections ||= begin
|
52
|
-
maybe_these = associated_class.reflections.keys
|
53
|
-
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:inverse_of].to_s)
|
54
|
-
end
|
55
|
-
else
|
56
|
-
[]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
class InverseOfAssociationRecursiveError < ActiveRecordError # :nodoc:
|
63
|
-
attr_reader :reflection
|
64
|
-
def initialize(reflection = nil)
|
65
|
-
if reflection
|
66
|
-
@reflection = reflection
|
67
|
-
super("Inverse association #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{reflection.class_name}) is recursive.")
|
68
|
-
else
|
69
|
-
super("Inverse association is recursive.")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class HasManyThroughAssociationNotFoundError < ActiveRecordError # :nodoc:
|
75
|
-
attr_reader :owner_class, :reflection
|
76
|
-
|
77
|
-
def initialize(owner_class = nil, reflection = nil)
|
78
|
-
if owner_class && reflection
|
79
|
-
@owner_class = owner_class
|
80
|
-
@reflection = reflection
|
81
|
-
super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class.name}")
|
82
|
-
else
|
83
|
-
super("Could not find the association.")
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
88
|
-
include DidYouMean::Correctable
|
89
|
-
|
90
|
-
def corrections
|
91
|
-
if owner_class && reflection
|
92
|
-
@corrections ||= begin
|
93
|
-
maybe_these = owner_class.reflections.keys
|
94
|
-
maybe_these -= [reflection.name.to_s] # remove failing reflection
|
95
|
-
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(reflection.options[:through].to_s)
|
96
|
-
end
|
97
|
-
else
|
98
|
-
[]
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError # :nodoc:
|
105
|
-
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
106
|
-
if owner_class_name && reflection && source_reflection
|
107
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}' without 'source_type'. Try adding 'source_type: \"#{reflection.name.to_s.classify}\"' to 'has_many :through' definition.")
|
108
|
-
else
|
109
|
-
super("Cannot have a has_many :through association.")
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
class HasManyThroughAssociationPolymorphicThroughError < ActiveRecordError # :nodoc:
|
115
|
-
def initialize(owner_class_name = nil, reflection = nil)
|
116
|
-
if owner_class_name && reflection
|
117
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
|
118
|
-
else
|
119
|
-
super("Cannot have a has_many :through association.")
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError # :nodoc:
|
125
|
-
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
126
|
-
if owner_class_name && reflection && source_reflection
|
127
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
|
128
|
-
else
|
129
|
-
super("Cannot have a has_many :through association.")
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
class HasOneThroughCantAssociateThroughCollection < ActiveRecordError # :nodoc:
|
135
|
-
def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
|
136
|
-
if owner_class_name && reflection && through_reflection
|
137
|
-
super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' where the :through association '#{owner_class_name}##{through_reflection.name}' is a collection. Specify a has_one or belongs_to association in the :through option instead.")
|
138
|
-
else
|
139
|
-
super("Cannot have a has_one :through association.")
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
class HasOneAssociationPolymorphicThroughError < ActiveRecordError # :nodoc:
|
145
|
-
def initialize(owner_class_name = nil, reflection = nil)
|
146
|
-
if owner_class_name && reflection
|
147
|
-
super("Cannot have a has_one :through association '#{owner_class_name}##{reflection.name}' which goes through the polymorphic association '#{owner_class_name}##{reflection.through_reflection.name}'.")
|
148
|
-
else
|
149
|
-
super("Cannot have a has_one :through association.")
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError # :nodoc:
|
155
|
-
def initialize(reflection = nil)
|
156
|
-
if reflection
|
157
|
-
through_reflection = reflection.through_reflection
|
158
|
-
source_reflection_names = reflection.source_reflection_names
|
159
|
-
source_associations = reflection.through_reflection.klass._reflections.keys
|
160
|
-
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')} in model #{through_reflection.klass}. Try 'has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}, :source => <name>'. Is it one of #{source_associations.to_sentence(two_words_connector: ' or ', last_word_connector: ', or ')}?")
|
161
|
-
else
|
162
|
-
super("Could not find the source association(s).")
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
class HasManyThroughOrderError < ActiveRecordError # :nodoc:
|
168
|
-
def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
|
169
|
-
if owner_class_name && reflection && through_reflection
|
170
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' which goes through '#{owner_class_name}##{through_reflection.name}' before the through association is defined.")
|
171
|
-
else
|
172
|
-
super("Cannot have a has_many :through association before the through association is defined.")
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
class ThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError # :nodoc:
|
178
|
-
def initialize(owner = nil, reflection = nil)
|
179
|
-
if owner && reflection
|
180
|
-
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because the source reflection class '#{reflection.source_reflection.class_name}' is associated to '#{reflection.through_reflection.class_name}' via :#{reflection.source_reflection.macro}.")
|
181
|
-
else
|
182
|
-
super("Cannot modify association.")
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
class CompositePrimaryKeyMismatchError < ActiveRecordError # :nodoc:
|
188
|
-
attr_reader :reflection
|
189
|
-
|
190
|
-
def initialize(reflection = nil)
|
191
|
-
if reflection
|
192
|
-
if reflection.has_one? || reflection.collection?
|
193
|
-
super("Association #{reflection.active_record}##{reflection.name} primary key #{reflection.active_record_primary_key} doesn't match with foreign key #{reflection.foreign_key}. Please specify query_constraints, or primary_key and foreign_key values.")
|
194
|
-
else
|
195
|
-
super("Association #{reflection.active_record}##{reflection.name} primary key #{reflection.association_primary_key} doesn't match with foreign key #{reflection.foreign_key}. Please specify query_constraints, or primary_key and foreign_key values.")
|
196
|
-
end
|
197
|
-
else
|
198
|
-
super("Association primary key doesn't match with foreign key.")
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
class AmbiguousSourceReflectionForThroughAssociation < ActiveRecordError # :nodoc:
|
204
|
-
def initialize(klass, macro, association_name, options, possible_sources)
|
205
|
-
example_options = options.dup
|
206
|
-
example_options[:source] = possible_sources.first
|
207
|
-
|
208
|
-
super("Ambiguous source reflection for through association. Please " \
|
209
|
-
"specify a :source directive on your declaration like:\n" \
|
210
|
-
"\n" \
|
211
|
-
" class #{klass} < ActiveRecord::Base\n" \
|
212
|
-
" #{macro} :#{association_name}, #{example_options}\n" \
|
213
|
-
" end"
|
214
|
-
)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection # :nodoc:
|
219
|
-
end
|
220
|
-
|
221
|
-
class HasOneThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection # :nodoc:
|
222
|
-
end
|
223
|
-
|
224
|
-
class ThroughNestedAssociationsAreReadonly < ActiveRecordError # :nodoc:
|
225
|
-
def initialize(owner = nil, reflection = nil)
|
226
|
-
if owner && reflection
|
227
|
-
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
|
228
|
-
else
|
229
|
-
super("Through nested associations are read-only.")
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
class HasManyThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly # :nodoc:
|
235
|
-
end
|
236
|
-
|
237
|
-
class HasOneThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly # :nodoc:
|
238
|
-
end
|
239
|
-
|
240
|
-
# This error is raised when trying to eager load a polymorphic association using a JOIN.
|
241
|
-
# Eager loading polymorphic associations is only possible with
|
242
|
-
# {ActiveRecord::Relation#preload}[rdoc-ref:QueryMethods#preload].
|
243
|
-
class EagerLoadPolymorphicError < ActiveRecordError
|
244
|
-
def initialize(reflection = nil)
|
245
|
-
if reflection
|
246
|
-
super("Cannot eagerly load the polymorphic association #{reflection.name.inspect}")
|
247
|
-
else
|
248
|
-
super("Eager load polymorphic error.")
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
# This error is raised when trying to destroy a parent instance in N:1 or 1:1 associations
|
254
|
-
# (has_many, has_one) when there is at least 1 child associated instance.
|
255
|
-
# ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
|
256
|
-
class DeleteRestrictionError < ActiveRecordError # :nodoc:
|
257
|
-
def initialize(name = nil)
|
258
|
-
if name
|
259
|
-
super("Cannot delete record because of dependent #{name}")
|
260
|
-
else
|
261
|
-
super("Delete restriction error.")
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
4
|
# See ActiveRecord::Associations::ClassMethods for documentation.
|
267
5
|
module Associations # :nodoc:
|
268
6
|
extend ActiveSupport::Autoload
|
@@ -641,21 +379,43 @@ module ActiveRecord
|
|
641
379
|
# after_add: :congratulate_client,
|
642
380
|
# after_remove: :log_after_remove
|
643
381
|
#
|
644
|
-
# def congratulate_client(
|
382
|
+
# def congratulate_client(client)
|
645
383
|
# # ...
|
646
384
|
# end
|
647
385
|
#
|
648
|
-
# def log_after_remove(
|
386
|
+
# def log_after_remove(client)
|
649
387
|
# # ...
|
650
388
|
# end
|
651
389
|
# end
|
652
390
|
#
|
391
|
+
# Callbacks can be defined in three ways:
|
392
|
+
#
|
393
|
+
# 1. A symbol that references a method defined on the class with the
|
394
|
+
# associated collection. For example, <tt>after_add: :congratulate_client</tt>
|
395
|
+
# invokes <tt>Firm#congratulate_client(client)</tt>.
|
396
|
+
# 2. A callable with a signature that accepts both the record with the
|
397
|
+
# associated collection and the record being added or removed. For
|
398
|
+
# example, <tt>after_add: ->(firm, client) { ... }</tt>.
|
399
|
+
# 3. An object that responds to the callback name. For example, passing
|
400
|
+
# <tt>after_add: CallbackObject.new</tt> invokes <tt>CallbackObject#after_add(firm,
|
401
|
+
# client)</tt>.
|
402
|
+
#
|
653
403
|
# It's possible to stack callbacks by passing them as an array. Example:
|
654
404
|
#
|
405
|
+
# class CallbackObject
|
406
|
+
# def after_add(firm, client)
|
407
|
+
# firm.log << "after_adding #{client.id}"
|
408
|
+
# end
|
409
|
+
# end
|
410
|
+
#
|
655
411
|
# class Firm < ActiveRecord::Base
|
656
412
|
# has_many :clients,
|
657
413
|
# dependent: :destroy,
|
658
|
-
# after_add: [
|
414
|
+
# after_add: [
|
415
|
+
# :congratulate_client,
|
416
|
+
# -> (firm, client) { firm.log << "after_adding #{client.id}" },
|
417
|
+
# CallbackObject.new
|
418
|
+
# ],
|
659
419
|
# after_remove: :log_after_remove
|
660
420
|
# end
|
661
421
|
#
|
@@ -799,7 +559,7 @@ module ActiveRecord
|
|
799
559
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
800
560
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
801
561
|
#
|
802
|
-
#
|
562
|
+
# === Setting Inverses
|
803
563
|
#
|
804
564
|
# If you are using a #belongs_to on the join model, it is a good idea to set the
|
805
565
|
# <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
|
@@ -1461,8 +1221,11 @@ module ActiveRecord
|
|
1461
1221
|
# If you are going to modify the association (rather than just read from it), then it is
|
1462
1222
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
1463
1223
|
# join model. This allows associated records to be built which will automatically create
|
1464
|
-
# the appropriate join model records when they are saved.
|
1465
|
-
#
|
1224
|
+
# the appropriate join model records when they are saved. See
|
1225
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
1226
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
1227
|
+
# more detail.
|
1228
|
+
#
|
1466
1229
|
# [+:disable_joins+]
|
1467
1230
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1468
1231
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
@@ -1491,7 +1254,8 @@ module ActiveRecord
|
|
1491
1254
|
# [+:inverse_of+]
|
1492
1255
|
# Specifies the name of the #belongs_to association on the associated object
|
1493
1256
|
# that is the inverse of this #has_many association.
|
1494
|
-
# See
|
1257
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1258
|
+
# for more detail.
|
1495
1259
|
# [+:extend+]
|
1496
1260
|
# Specifies a module or array of modules that will be extended into the association object returned.
|
1497
1261
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
@@ -1507,10 +1271,20 @@ module ActiveRecord
|
|
1507
1271
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
1508
1272
|
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
1509
1273
|
# [+:index_errors+]
|
1510
|
-
#
|
1274
|
+
# Allows differentiation of multiple validation errors from the association records, by including
|
1511
1275
|
# an index in the error attribute name, e.g. +roles[2].level+.
|
1512
|
-
#
|
1276
|
+
# When set to +true+, the index is based on association order, i.e. database order, with yet to be
|
1513
1277
|
# persisted new records placed at the end.
|
1278
|
+
# When set to +:nested_attributes_order+, the index is based on the record order received by
|
1279
|
+
# nested attributes setter, when accepts_nested_attributes_for is used.
|
1280
|
+
# [:before_add]
|
1281
|
+
# Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>before an object is added</b> to the association collection.
|
1282
|
+
# [:after_add]
|
1283
|
+
# Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>after an object is added</b> to the association collection.
|
1284
|
+
# [:before_remove]
|
1285
|
+
# 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
|
+
# [:after_remove]
|
1287
|
+
# Defines an {association callback}[rdoc-ref:Associations::ClassMethods@Association+callbacks] that gets triggered <b>after an object is removed</b> from the association collection.
|
1514
1288
|
#
|
1515
1289
|
# Option examples:
|
1516
1290
|
# has_many :comments, -> { order("posted_on") }
|
@@ -1524,16 +1298,18 @@ module ActiveRecord
|
|
1524
1298
|
# has_many :subscribers, through: :subscriptions, disable_joins: true
|
1525
1299
|
# has_many :comments, strict_loading: true
|
1526
1300
|
# has_many :comments, query_constraints: [:blog_id, :post_id]
|
1527
|
-
# has_many :comments, index_errors:
|
1301
|
+
# has_many :comments, index_errors: :nested_attributes_order
|
1528
1302
|
def has_many(name, scope = nil, **options, &extension)
|
1529
1303
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
1530
1304
|
Reflection.add_reflection self, name, reflection
|
1531
1305
|
end
|
1532
1306
|
|
1533
|
-
# Specifies a one-to-one association with another class. This method
|
1534
|
-
# if the other class contains the foreign key. If
|
1535
|
-
#
|
1536
|
-
#
|
1307
|
+
# Specifies a one-to-one association with another class. This method
|
1308
|
+
# should only be used if the other class contains the foreign key. If
|
1309
|
+
# the current class contains the foreign key, then you should use
|
1310
|
+
# #belongs_to instead. See {Is it a belongs_to or has_one
|
1311
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
1312
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
1537
1313
|
#
|
1538
1314
|
# The following methods for retrieval and query of a single associated object will be added:
|
1539
1315
|
#
|
@@ -1648,8 +1424,10 @@ module ActiveRecord
|
|
1648
1424
|
# If you are going to modify the association (rather than just read from it), then it is
|
1649
1425
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
1650
1426
|
# join model. This allows associated records to be built which will automatically create
|
1651
|
-
# the appropriate join model records when they are saved.
|
1652
|
-
#
|
1427
|
+
# the appropriate join model records when they are saved. See
|
1428
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
1429
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
1430
|
+
# more detail.
|
1653
1431
|
# [+:disable_joins+]
|
1654
1432
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
1655
1433
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
@@ -1667,9 +1445,14 @@ module ActiveRecord
|
|
1667
1445
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
1668
1446
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
1669
1447
|
# [+:autosave+]
|
1670
|
-
# If true
|
1671
|
-
# when saving the parent object.
|
1672
|
-
#
|
1448
|
+
# If +true+, always saves the associated object or destroys it if marked for destruction,
|
1449
|
+
# when saving the parent object.
|
1450
|
+
# If +false+, never save or destroy the associated object.
|
1451
|
+
#
|
1452
|
+
# By default, only saves the associated object if it's a new record. Setting this option
|
1453
|
+
# to +true+ also enables validations on the associated object unless explicitly disabled
|
1454
|
+
# with <tt>validate: false</tt>. This is because saving an object with invalid associated
|
1455
|
+
# objects would fail, so any associated objects will go through validation checks.
|
1673
1456
|
#
|
1674
1457
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
1675
1458
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
@@ -1682,7 +1465,8 @@ module ActiveRecord
|
|
1682
1465
|
# [+:inverse_of+]
|
1683
1466
|
# Specifies the name of the #belongs_to association on the associated object
|
1684
1467
|
# that is the inverse of this #has_one association.
|
1685
|
-
# See
|
1468
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1469
|
+
# for more detail.
|
1686
1470
|
# [+:required+]
|
1687
1471
|
# When set to +true+, the association will also have its presence validated.
|
1688
1472
|
# This will validate the association itself, not the id. You can use
|
@@ -1716,10 +1500,12 @@ module ActiveRecord
|
|
1716
1500
|
Reflection.add_reflection self, name, reflection
|
1717
1501
|
end
|
1718
1502
|
|
1719
|
-
# Specifies a one-to-one association with another class. This method
|
1720
|
-
# if this class contains the foreign key. If the
|
1721
|
-
# then you should use #has_one
|
1722
|
-
#
|
1503
|
+
# Specifies a one-to-one association with another class. This method
|
1504
|
+
# should only be used if this class contains the foreign key. If the
|
1505
|
+
# other class contains the foreign key, then you should use #has_one
|
1506
|
+
# instead. See {Is it a belongs_to or has_one
|
1507
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
1508
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
1723
1509
|
#
|
1724
1510
|
# Methods will be added for retrieval and query for a single associated object, for which
|
1725
1511
|
# this object holds an id:
|
@@ -1822,15 +1608,25 @@ module ActiveRecord
|
|
1822
1608
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
1823
1609
|
# is used on the associate class (such as a Post class) - that is the migration for
|
1824
1610
|
# <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
|
1825
|
-
# return the count cached
|
1611
|
+
# return the count cached). You can also specify a custom counter
|
1826
1612
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
1827
1613
|
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
1828
|
-
#
|
1829
|
-
#
|
1830
|
-
#
|
1831
|
-
#
|
1614
|
+
#
|
1615
|
+
# Starting to use counter caches on existing large tables can be troublesome, because the column
|
1616
|
+
# values must be backfilled separately of the column addition (to not lock the table for too long)
|
1617
|
+
# and before the use of +:counter_cache+ (otherwise methods like +size+/+any?+/etc, which use
|
1618
|
+
# counter caches internally, can produce incorrect results). To safely backfill the values while keeping
|
1619
|
+
# counter cache columns updated with the child records creation/removal and to avoid the mentioned methods
|
1620
|
+
# use the possibly incorrect counter cache column values and always get the results from the database,
|
1621
|
+
# use <tt>counter_cache: { active: false }</tt>.
|
1622
|
+
# If you also need to specify a custom column name, use <tt>counter_cache: { active: false, column: :my_custom_counter }</tt>.
|
1623
|
+
#
|
1832
1624
|
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
1833
1625
|
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
1626
|
+
# [+:polymorphic+]
|
1627
|
+
# Specify this association is a polymorphic association by passing +true+.
|
1628
|
+
# Note: Since polymorphic associations rely on storing class names in the database, make sure to update the class names in the
|
1629
|
+
# <tt>*_type</tt> polymorphic type column of the corresponding rows.
|
1834
1630
|
# [+:validate+]
|
1835
1631
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
1836
1632
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
@@ -1851,7 +1647,8 @@ module ActiveRecord
|
|
1851
1647
|
# [+:inverse_of+]
|
1852
1648
|
# Specifies the name of the #has_one or #has_many association on the associated
|
1853
1649
|
# object that is the inverse of this #belongs_to association.
|
1854
|
-
# See
|
1650
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
1651
|
+
# for more detail.
|
1855
1652
|
# [+:optional+]
|
1856
1653
|
# When set to +true+, the association will not have its presence validated.
|
1857
1654
|
# [+:required+]
|
@@ -1888,7 +1685,7 @@ module ActiveRecord
|
|
1888
1685
|
# belongs_to :user, optional: true
|
1889
1686
|
# belongs_to :account, default: -> { company.account }
|
1890
1687
|
# belongs_to :account, strict_loading: true
|
1891
|
-
#
|
1688
|
+
# belongs_to :note, query_constraints: [:organization_id, :note_id]
|
1892
1689
|
def belongs_to(name, scope = nil, **options)
|
1893
1690
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
1894
1691
|
Reflection.add_reflection self, name, reflection
|
@@ -1911,7 +1708,7 @@ module ActiveRecord
|
|
1911
1708
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
1912
1709
|
# join table with a migration such as this:
|
1913
1710
|
#
|
1914
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[
|
1711
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[8.0]
|
1915
1712
|
# def change
|
1916
1713
|
# create_join_table :developers, :projects
|
1917
1714
|
# end
|
@@ -2105,7 +1902,7 @@ module ActiveRecord
|
|
2105
1902
|
end
|
2106
1903
|
|
2107
1904
|
has_many name, scope, **hm_options, &extension
|
2108
|
-
_reflections[name
|
1905
|
+
_reflections[name].parent_reflection = habtm_reflection
|
2109
1906
|
end
|
2110
1907
|
end
|
2111
1908
|
end
|
@@ -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
|