activerecord 7.1.5.2 → 8.1.2.1
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 +567 -2443
- data/README.rdoc +16 -16
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +3 -2
- 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 +31 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +23 -11
- data/lib/active_record/associations/builder/belongs_to.rb +18 -4
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- 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/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +36 -5
- 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 +268 -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/join_dependency.rb +4 -2
- 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/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +8 -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 +250 -315
- 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/query.rb +34 -0
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +20 -27
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +96 -68
- data/lib/active_record/autosave_association.rb +93 -58
- data/lib/active_record/base.rb +5 -7
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
- data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
- 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 +136 -34
- data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- 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 +79 -46
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
- 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/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
- 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 +44 -41
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
- data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
- 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 +43 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +66 -0
- data/lib/active_record/connection_handling.rb +88 -46
- data/lib/active_record/core.rb +142 -58
- data/lib/active_record/counter_cache.rb +52 -18
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +28 -5
- data/lib/active_record/database_configurations/hash_config.rb +103 -41
- data/lib/active_record/database_configurations/url_config.rb +30 -1
- data/lib/active_record/database_configurations.rb +8 -4
- data/lib/active_record/delegated_type.rb +43 -19
- data/lib/active_record/dynamic_matchers.rb +56 -71
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +12 -12
- data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
- data/lib/active_record/encryption/encryptor.rb +58 -22
- 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 +9 -2
- data/lib/active_record/enum.rb +57 -36
- data/lib/active_record/errors.rb +76 -26
- data/lib/active_record/explain.rb +14 -25
- 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 +39 -35
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +5 -3
- data/lib/active_record/insert_all.rb +28 -20
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +15 -7
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +3 -34
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +46 -14
- data/lib/active_record/migration/compatibility.rb +40 -25
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- 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 +119 -103
- data/lib/active_record/model_schema.rb +66 -78
- data/lib/active_record/nested_attributes.rb +17 -9
- data/lib/active_record/persistence.rb +161 -454
- data/lib/active_record/query_cache.rb +33 -15
- data/lib/active_record/query_logs.rb +106 -39
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +28 -16
- data/lib/active_record/railtie.rb +61 -74
- data/lib/active_record/railties/controller_runtime.rb +19 -5
- data/lib/active_record/railties/databases.rake +64 -78
- 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 +147 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +153 -73
- data/lib/active_record/relation/calculations.rb +146 -96
- data/lib/active_record/relation/delegation.rb +30 -23
- data/lib/active_record/relation/finder_methods.rb +64 -34
- 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 +19 -11
- 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 +25 -10
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +351 -124
- data/lib/active_record/relation/spawn_methods.rb +9 -25
- data/lib/active_record/relation/where_clause.rb +17 -30
- data/lib/active_record/relation.rb +590 -124
- data/lib/active_record/result.rb +131 -59
- data/lib/active_record/runtime_registry.rb +44 -21
- data/lib/active_record/sanitization.rb +33 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +66 -31
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -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 +68 -20
- data/lib/active_record/statement_cache.rb +29 -25
- 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 +7 -33
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +118 -90
- 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 +17 -28
- data/lib/active_record/test_databases.rb +14 -4
- data/lib/active_record/test_fixtures.rb +123 -89
- data/lib/active_record/testing/query_assertions.rb +127 -0
- data/lib/active_record/timestamp.rb +6 -4
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +129 -0
- data/lib/active_record/transactions.rb +97 -18
- data/lib/active_record/translation.rb +0 -2
- 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 +12 -7
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +5 -4
- data/lib/active_record/validations/associated.rb +10 -4
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +203 -59
- data/lib/arel/alias_predication.rb +3 -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/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- 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/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +6 -5
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +2 -4
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +14 -5
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +7 -1
- data/lib/arel/visitors/dot.rb +3 -3
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +56 -12
- data/lib/arel/visitors/sqlite.rb +80 -8
- data/lib/arel/visitors/to_sql.rb +34 -37
- data/lib/arel.rb +10 -4
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +23 -14
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -167
- 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
|
|
@@ -301,6 +39,8 @@ module ActiveRecord
|
|
|
301
39
|
autoload :AssociationScope
|
|
302
40
|
autoload :DisableJoinsAssociationScope
|
|
303
41
|
autoload :AliasTracker
|
|
42
|
+
|
|
43
|
+
autoload :Deprecation
|
|
304
44
|
end
|
|
305
45
|
|
|
306
46
|
def self.eager_load!
|
|
@@ -341,7 +81,7 @@ module ActiveRecord
|
|
|
341
81
|
|
|
342
82
|
# Returns the specified association instance if it exists, +nil+ otherwise.
|
|
343
83
|
def association_instance_get(name)
|
|
344
|
-
@association_cache[name]
|
|
84
|
+
(@association_cache ||= {})[name]
|
|
345
85
|
end
|
|
346
86
|
|
|
347
87
|
# Set the specified association instance.
|
|
@@ -349,6 +89,14 @@ module ActiveRecord
|
|
|
349
89
|
@association_cache[name] = association
|
|
350
90
|
end
|
|
351
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
|
+
|
|
352
100
|
# = Active Record \Associations
|
|
353
101
|
#
|
|
354
102
|
# \Associations are a set of macro-like class methods for tying objects together through
|
|
@@ -641,21 +389,43 @@ module ActiveRecord
|
|
|
641
389
|
# after_add: :congratulate_client,
|
|
642
390
|
# after_remove: :log_after_remove
|
|
643
391
|
#
|
|
644
|
-
# def congratulate_client(
|
|
392
|
+
# def congratulate_client(client)
|
|
645
393
|
# # ...
|
|
646
394
|
# end
|
|
647
395
|
#
|
|
648
|
-
# def log_after_remove(
|
|
396
|
+
# def log_after_remove(client)
|
|
649
397
|
# # ...
|
|
650
398
|
# end
|
|
651
399
|
# end
|
|
652
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
|
+
#
|
|
653
413
|
# It's possible to stack callbacks by passing them as an array. Example:
|
|
654
414
|
#
|
|
415
|
+
# class CallbackObject
|
|
416
|
+
# def after_add(firm, client)
|
|
417
|
+
# firm.log << "after_adding #{client.id}"
|
|
418
|
+
# end
|
|
419
|
+
# end
|
|
420
|
+
#
|
|
655
421
|
# class Firm < ActiveRecord::Base
|
|
656
422
|
# has_many :clients,
|
|
657
423
|
# dependent: :destroy,
|
|
658
|
-
# after_add: [
|
|
424
|
+
# after_add: [
|
|
425
|
+
# :congratulate_client,
|
|
426
|
+
# -> (firm, client) { firm.log << "after_adding #{client.id}" },
|
|
427
|
+
# CallbackObject.new
|
|
428
|
+
# ],
|
|
659
429
|
# after_remove: :log_after_remove
|
|
660
430
|
# end
|
|
661
431
|
#
|
|
@@ -799,7 +569,7 @@ module ActiveRecord
|
|
|
799
569
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
|
800
570
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
|
801
571
|
#
|
|
802
|
-
#
|
|
572
|
+
# === Setting Inverses
|
|
803
573
|
#
|
|
804
574
|
# If you are using a #belongs_to on the join model, it is a good idea to set the
|
|
805
575
|
# <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
|
|
@@ -1260,6 +1030,116 @@ module ActiveRecord
|
|
|
1260
1030
|
# associated records themselves, you can always do something along the lines of
|
|
1261
1031
|
# <tt>person.tasks.each(&:destroy)</tt>.
|
|
1262
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
|
+
#
|
|
1263
1143
|
# == Type safety with ActiveRecord::AssociationTypeMismatch
|
|
1264
1144
|
#
|
|
1265
1145
|
# If you attempt to assign an object to an association that doesn't match the inferred
|
|
@@ -1448,8 +1328,10 @@ module ActiveRecord
|
|
|
1448
1328
|
# [+:as+]
|
|
1449
1329
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1450
1330
|
# [+:through+]
|
|
1451
|
-
# Specifies an association through which to perform the query.
|
|
1452
|
-
#
|
|
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>,
|
|
1453
1335
|
# <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
|
|
1454
1336
|
# source reflection.
|
|
1455
1337
|
#
|
|
@@ -1461,8 +1343,11 @@ module ActiveRecord
|
|
|
1461
1343
|
# If you are going to modify the association (rather than just read from it), then it is
|
|
1462
1344
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
|
1463
1345
|
# join model. This allows associated records to be built which will automatically create
|
|
1464
|
-
# the appropriate join model records when they are saved.
|
|
1465
|
-
#
|
|
1346
|
+
# the appropriate join model records when they are saved. See
|
|
1347
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
|
1348
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
|
1349
|
+
# more detail.
|
|
1350
|
+
#
|
|
1466
1351
|
# [+:disable_joins+]
|
|
1467
1352
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
|
1468
1353
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
|
@@ -1491,7 +1376,8 @@ module ActiveRecord
|
|
|
1491
1376
|
# [+:inverse_of+]
|
|
1492
1377
|
# Specifies the name of the #belongs_to association on the associated object
|
|
1493
1378
|
# that is the inverse of this #has_many association.
|
|
1494
|
-
# See
|
|
1379
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
|
1380
|
+
# for more detail.
|
|
1495
1381
|
# [+:extend+]
|
|
1496
1382
|
# Specifies a module or array of modules that will be extended into the association object returned.
|
|
1497
1383
|
# Useful for defining methods on associations, especially when they should be shared between multiple
|
|
@@ -1507,10 +1393,23 @@ module ActiveRecord
|
|
|
1507
1393
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1508
1394
|
# When the value is set the Array size must match associated model's primary key or +query_constraints+ size.
|
|
1509
1395
|
# [+:index_errors+]
|
|
1510
|
-
#
|
|
1396
|
+
# Allows differentiation of multiple validation errors from the association records, by including
|
|
1511
1397
|
# an index in the error attribute name, e.g. +roles[2].level+.
|
|
1512
|
-
#
|
|
1398
|
+
# When set to +true+, the index is based on association order, i.e. database order, with yet to be
|
|
1513
1399
|
# persisted new records placed at the end.
|
|
1400
|
+
# When set to +:nested_attributes_order+, the index is based on the record order received by
|
|
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.
|
|
1514
1413
|
#
|
|
1515
1414
|
# Option examples:
|
|
1516
1415
|
# has_many :comments, -> { order("posted_on") }
|
|
@@ -1524,16 +1423,18 @@ module ActiveRecord
|
|
|
1524
1423
|
# has_many :subscribers, through: :subscriptions, disable_joins: true
|
|
1525
1424
|
# has_many :comments, strict_loading: true
|
|
1526
1425
|
# has_many :comments, query_constraints: [:blog_id, :post_id]
|
|
1527
|
-
# has_many :comments, index_errors:
|
|
1426
|
+
# has_many :comments, index_errors: :nested_attributes_order
|
|
1528
1427
|
def has_many(name, scope = nil, **options, &extension)
|
|
1529
1428
|
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
|
1530
|
-
Reflection.add_reflection
|
|
1429
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1531
1430
|
end
|
|
1532
1431
|
|
|
1533
|
-
# Specifies a one-to-one association with another class. This method
|
|
1534
|
-
# if the other class contains the foreign key. If
|
|
1535
|
-
#
|
|
1536
|
-
#
|
|
1432
|
+
# Specifies a one-to-one association with another class. This method
|
|
1433
|
+
# should only be used if the other class contains the foreign key. If
|
|
1434
|
+
# the current class contains the foreign key, then you should use
|
|
1435
|
+
# #belongs_to instead. See {Is it a belongs_to or has_one
|
|
1436
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
|
1437
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
|
1537
1438
|
#
|
|
1538
1439
|
# The following methods for retrieval and query of a single associated object will be added:
|
|
1539
1440
|
#
|
|
@@ -1635,10 +1536,12 @@ module ActiveRecord
|
|
|
1635
1536
|
# [+:as+]
|
|
1636
1537
|
# Specifies a polymorphic interface (See #belongs_to).
|
|
1637
1538
|
# [+:through+]
|
|
1638
|
-
# Specifies
|
|
1639
|
-
#
|
|
1640
|
-
#
|
|
1641
|
-
#
|
|
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.
|
|
1642
1545
|
#
|
|
1643
1546
|
# If the association on the join model is a #belongs_to, the collection can be modified
|
|
1644
1547
|
# and the records on the <tt>:through</tt> model will be automatically created and removed
|
|
@@ -1648,8 +1551,10 @@ module ActiveRecord
|
|
|
1648
1551
|
# If you are going to modify the association (rather than just read from it), then it is
|
|
1649
1552
|
# a good idea to set the <tt>:inverse_of</tt> option on the source association on the
|
|
1650
1553
|
# join model. This allows associated records to be built which will automatically create
|
|
1651
|
-
# the appropriate join model records when they are saved.
|
|
1652
|
-
#
|
|
1554
|
+
# the appropriate join model records when they are saved. See
|
|
1555
|
+
# {Association Join Models}[rdoc-ref:Associations::ClassMethods@Association+Join+Models]
|
|
1556
|
+
# and {Setting Inverses}[rdoc-ref:Associations::ClassMethods@Setting+Inverses] for
|
|
1557
|
+
# more detail.
|
|
1653
1558
|
# [+:disable_joins+]
|
|
1654
1559
|
# Specifies whether joins should be skipped for an association. If set to true, two or more queries
|
|
1655
1560
|
# will be generated. Note that in some cases, if order or limit is applied, it will be done in-memory
|
|
@@ -1667,9 +1572,14 @@ module ActiveRecord
|
|
|
1667
1572
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
|
1668
1573
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
|
1669
1574
|
# [+:autosave+]
|
|
1670
|
-
# If true
|
|
1671
|
-
# when saving the parent object.
|
|
1672
|
-
#
|
|
1575
|
+
# If +true+, always saves the associated object or destroys it if marked for destruction,
|
|
1576
|
+
# when saving the parent object.
|
|
1577
|
+
# If +false+, never save or destroy the associated object.
|
|
1578
|
+
#
|
|
1579
|
+
# By default, only saves the associated object if it's a new record. Setting this option
|
|
1580
|
+
# to +true+ also enables validations on the associated object unless explicitly disabled
|
|
1581
|
+
# with <tt>validate: false</tt>. This is because saving an object with invalid associated
|
|
1582
|
+
# objects would fail, so any associated objects will go through validation checks.
|
|
1673
1583
|
#
|
|
1674
1584
|
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
|
1675
1585
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
|
@@ -1682,7 +1592,8 @@ module ActiveRecord
|
|
|
1682
1592
|
# [+:inverse_of+]
|
|
1683
1593
|
# Specifies the name of the #belongs_to association on the associated object
|
|
1684
1594
|
# that is the inverse of this #has_one association.
|
|
1685
|
-
# See
|
|
1595
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
|
1596
|
+
# for more detail.
|
|
1686
1597
|
# [+:required+]
|
|
1687
1598
|
# When set to +true+, the association will also have its presence validated.
|
|
1688
1599
|
# This will validate the association itself, not the id. You can use
|
|
@@ -1696,12 +1607,15 @@ module ActiveRecord
|
|
|
1696
1607
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1697
1608
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1698
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.
|
|
1699
1613
|
#
|
|
1700
1614
|
# Option examples:
|
|
1701
1615
|
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
|
1702
1616
|
# has_one :credit_card, dependent: :nullify # updates the associated records foreign
|
|
1703
1617
|
# # key value to NULL rather than destroying it
|
|
1704
|
-
# has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
|
|
1618
|
+
# has_one :last_comment, -> { order('posted_on desc') }, class_name: "Comment"
|
|
1705
1619
|
# has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
|
|
1706
1620
|
# has_one :attachment, as: :attachable
|
|
1707
1621
|
# has_one :boss, -> { readonly }
|
|
@@ -1713,13 +1627,15 @@ module ActiveRecord
|
|
|
1713
1627
|
# has_one :employment_record_book, query_constraints: [:organization_id, :employee_id]
|
|
1714
1628
|
def has_one(name, scope = nil, **options)
|
|
1715
1629
|
reflection = Builder::HasOne.build(self, name, scope, options)
|
|
1716
|
-
Reflection.add_reflection
|
|
1630
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1717
1631
|
end
|
|
1718
1632
|
|
|
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
|
-
#
|
|
1633
|
+
# Specifies a one-to-one association with another class. This method
|
|
1634
|
+
# should only be used if this class contains the foreign key. If the
|
|
1635
|
+
# other class contains the foreign key, then you should use #has_one
|
|
1636
|
+
# instead. See {Is it a belongs_to or has_one
|
|
1637
|
+
# association?}[rdoc-ref:Associations::ClassMethods@Is+it+a+-23belongs_to+or+-23has_one+association-3F]
|
|
1638
|
+
# for more detail on when to use #has_one and when to use #belongs_to.
|
|
1723
1639
|
#
|
|
1724
1640
|
# Methods will be added for retrieval and query for a single associated object, for which
|
|
1725
1641
|
# this object holds an id:
|
|
@@ -1790,7 +1706,9 @@ module ActiveRecord
|
|
|
1790
1706
|
# [+:class_name+]
|
|
1791
1707
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
|
1792
1708
|
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
|
|
1793
|
-
# 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.
|
|
1794
1712
|
# [+:foreign_key+]
|
|
1795
1713
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
|
1796
1714
|
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
|
|
@@ -1822,15 +1740,25 @@ module ActiveRecord
|
|
|
1822
1740
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
|
1823
1741
|
# is used on the associate class (such as a Post class) - that is the migration for
|
|
1824
1742
|
# <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
|
|
1825
|
-
# return the count cached
|
|
1743
|
+
# return the count cached). You can also specify a custom counter
|
|
1826
1744
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
|
1827
1745
|
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
|
1828
|
-
#
|
|
1829
|
-
#
|
|
1830
|
-
#
|
|
1831
|
-
#
|
|
1746
|
+
#
|
|
1747
|
+
# Starting to use counter caches on existing large tables can be troublesome, because the column
|
|
1748
|
+
# values must be backfilled separately of the column addition (to not lock the table for too long)
|
|
1749
|
+
# and before the use of +:counter_cache+ (otherwise methods like +size+/+any?+/etc, which use
|
|
1750
|
+
# counter caches internally, can produce incorrect results). To safely backfill the values while keeping
|
|
1751
|
+
# counter cache columns updated with the child records creation/removal and to avoid the mentioned methods
|
|
1752
|
+
# use the possibly incorrect counter cache column values and always get the results from the database,
|
|
1753
|
+
# use <tt>counter_cache: { active: false }</tt>.
|
|
1754
|
+
# If you also need to specify a custom column name, use <tt>counter_cache: { active: false, column: :my_custom_counter }</tt>.
|
|
1755
|
+
#
|
|
1832
1756
|
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
|
1833
1757
|
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
|
1758
|
+
# [+:polymorphic+]
|
|
1759
|
+
# Specify this association is a polymorphic association by passing +true+.
|
|
1760
|
+
# Note: Since polymorphic associations rely on storing class names in the database, make sure to update the class names in the
|
|
1761
|
+
# <tt>*_type</tt> polymorphic type column of the corresponding rows.
|
|
1834
1762
|
# [+:validate+]
|
|
1835
1763
|
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
|
1836
1764
|
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
|
@@ -1851,7 +1779,8 @@ module ActiveRecord
|
|
|
1851
1779
|
# [+:inverse_of+]
|
|
1852
1780
|
# Specifies the name of the #has_one or #has_many association on the associated
|
|
1853
1781
|
# object that is the inverse of this #belongs_to association.
|
|
1854
|
-
# See
|
|
1782
|
+
# See {Bi-directional associations}[rdoc-ref:Associations::ClassMethods@Bi-directional+associations]
|
|
1783
|
+
# for more detail.
|
|
1855
1784
|
# [+:optional+]
|
|
1856
1785
|
# When set to +true+, the association will not have its presence validated.
|
|
1857
1786
|
# [+:required+]
|
|
@@ -1873,6 +1802,9 @@ module ActiveRecord
|
|
|
1873
1802
|
# Serves as a composite foreign key. Defines the list of columns to be used to query the associated object.
|
|
1874
1803
|
# This is an optional option. By default Rails will attempt to derive the value automatically.
|
|
1875
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.
|
|
1876
1808
|
#
|
|
1877
1809
|
# Option examples:
|
|
1878
1810
|
# belongs_to :firm, foreign_key: "client_of"
|
|
@@ -1888,10 +1820,10 @@ module ActiveRecord
|
|
|
1888
1820
|
# belongs_to :user, optional: true
|
|
1889
1821
|
# belongs_to :account, default: -> { company.account }
|
|
1890
1822
|
# belongs_to :account, strict_loading: true
|
|
1891
|
-
#
|
|
1823
|
+
# belongs_to :note, query_constraints: [:organization_id, :note_id]
|
|
1892
1824
|
def belongs_to(name, scope = nil, **options)
|
|
1893
1825
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
|
1894
|
-
Reflection.add_reflection
|
|
1826
|
+
Reflection.add_reflection(self, name, reflection)
|
|
1895
1827
|
end
|
|
1896
1828
|
|
|
1897
1829
|
# Specifies a many-to-many relationship with another class. This associates two classes via an
|
|
@@ -1911,7 +1843,7 @@ module ActiveRecord
|
|
|
1911
1843
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
|
1912
1844
|
# join table with a migration such as this:
|
|
1913
1845
|
#
|
|
1914
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[
|
|
1846
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[8.1]
|
|
1915
1847
|
# def change
|
|
1916
1848
|
# create_join_table :developers, :projects
|
|
1917
1849
|
# end
|
|
@@ -2062,6 +1994,9 @@ module ActiveRecord
|
|
|
2062
1994
|
# <tt>:autosave</tt> to <tt>true</tt>.
|
|
2063
1995
|
# [+:strict_loading+]
|
|
2064
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.
|
|
2065
2000
|
#
|
|
2066
2001
|
# Option examples:
|
|
2067
2002
|
# has_and_belongs_to_many :projects
|
|
@@ -2073,17 +2008,17 @@ module ActiveRecord
|
|
|
2073
2008
|
def has_and_belongs_to_many(name, scope = nil, **options, &extension)
|
|
2074
2009
|
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
|
2075
2010
|
|
|
2076
|
-
builder = Builder::HasAndBelongsToMany.new
|
|
2011
|
+
builder = Builder::HasAndBelongsToMany.new(name, self, options)
|
|
2077
2012
|
|
|
2078
2013
|
join_model = builder.through_model
|
|
2079
2014
|
|
|
2080
|
-
const_set
|
|
2081
|
-
private_constant
|
|
2015
|
+
const_set(join_model.name, join_model)
|
|
2016
|
+
private_constant(join_model.name)
|
|
2082
2017
|
|
|
2083
|
-
middle_reflection = builder.middle_reflection
|
|
2018
|
+
middle_reflection = builder.middle_reflection(join_model)
|
|
2084
2019
|
|
|
2085
|
-
Builder::HasMany.define_callbacks
|
|
2086
|
-
Reflection.add_reflection
|
|
2020
|
+
Builder::HasMany.define_callbacks(self, middle_reflection)
|
|
2021
|
+
Reflection.add_reflection(self, middle_reflection.name, middle_reflection)
|
|
2087
2022
|
middle_reflection.parent_reflection = habtm_reflection
|
|
2088
2023
|
|
|
2089
2024
|
include Module.new {
|
|
@@ -2100,12 +2035,12 @@ module ActiveRecord
|
|
|
2100
2035
|
hm_options[:through] = middle_reflection.name
|
|
2101
2036
|
hm_options[:source] = join_model.right_reflection.name
|
|
2102
2037
|
|
|
2103
|
-
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
|
|
2104
|
-
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)
|
|
2105
2040
|
end
|
|
2106
2041
|
|
|
2107
2042
|
has_many name, scope, **hm_options, &extension
|
|
2108
|
-
_reflections[name
|
|
2043
|
+
_reflections[name].parent_reflection = habtm_reflection
|
|
2109
2044
|
end
|
|
2110
2045
|
end
|
|
2111
2046
|
end
|