activerecord 3.2.19 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1715 -604
- data/MIT-LICENSE +2 -2
- data/README.rdoc +40 -45
- data/examples/performance.rb +33 -22
- data/examples/simple.rb +3 -4
- data/lib/active_record/aggregations.rb +76 -51
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +54 -40
- data/lib/active_record/associations/association.rb +76 -56
- data/lib/active_record/associations/association_scope.rb +125 -93
- data/lib/active_record/associations/belongs_to_association.rb +57 -28
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +120 -32
- data/lib/active_record/associations/builder/belongs_to.rb +115 -62
- data/lib/active_record/associations/builder/collection_association.rb +61 -53
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
- data/lib/active_record/associations/builder/has_many.rb +9 -65
- data/lib/active_record/associations/builder/has_one.rb +18 -52
- data/lib/active_record/associations/builder/singular_association.rb +18 -19
- data/lib/active_record/associations/collection_association.rb +268 -186
- data/lib/active_record/associations/collection_proxy.rb +1003 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +81 -41
- data/lib/active_record/associations/has_many_through_association.rb +76 -55
- data/lib/active_record/associations/has_one_association.rb +51 -21
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +239 -155
- data/lib/active_record/associations/preloader/association.rb +97 -62
- data/lib/active_record/associations/preloader/collection_association.rb +2 -8
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +75 -33
- data/lib/active_record/associations/preloader.rb +111 -79
- data/lib/active_record/associations/singular_association.rb +35 -13
- data/lib/active_record/associations/through_association.rb +41 -19
- data/lib/active_record/associations.rb +727 -501
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +213 -0
- data/lib/active_record/attribute_assignment.rb +32 -162
- data/lib/active_record/attribute_decorators.rb +67 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -61
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +7 -6
- data/lib/active_record/attribute_methods/read.rb +56 -117
- data/lib/active_record/attribute_methods/serialization.rb +43 -96
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
- data/lib/active_record/attribute_methods/write.rb +34 -45
- data/lib/active_record/attribute_methods.rb +333 -144
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +108 -0
- data/lib/active_record/attribute_set.rb +108 -0
- data/lib/active_record/attributes.rb +265 -0
- data/lib/active_record/autosave_association.rb +285 -223
- data/lib/active_record/base.rb +95 -490
- data/lib/active_record/callbacks.rb +95 -61
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +28 -19
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
- data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
- data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
- data/lib/active_record/connection_adapters/column.rb +30 -259
- data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
- data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
- data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +155 -0
- data/lib/active_record/core.rb +561 -0
- data/lib/active_record/counter_cache.rb +146 -105
- data/lib/active_record/dynamic_matchers.rb +101 -64
- data/lib/active_record/enum.rb +234 -0
- data/lib/active_record/errors.rb +153 -56
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +10 -6
- data/lib/active_record/fixture_set/file.rb +77 -0
- data/lib/active_record/fixtures.rb +355 -232
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +144 -79
- data/lib/active_record/integration.rb +66 -13
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +77 -56
- data/lib/active_record/locking/pessimistic.rb +6 -6
- data/lib/active_record/log_subscriber.rb +53 -28
- data/lib/active_record/migration/command_recorder.rb +166 -33
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +792 -264
- data/lib/active_record/model_schema.rb +192 -130
- data/lib/active_record/nested_attributes.rb +238 -145
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +89 -0
- data/lib/active_record/persistence.rb +357 -157
- data/lib/active_record/query_cache.rb +22 -43
- data/lib/active_record/querying.rb +34 -23
- data/lib/active_record/railtie.rb +88 -48
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +5 -4
- data/lib/active_record/railties/databases.rake +170 -422
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -5
- data/lib/active_record/reflection.rb +715 -189
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +203 -50
- data/lib/active_record/relation/calculations.rb +203 -194
- data/lib/active_record/relation/delegation.rb +103 -25
- data/lib/active_record/relation/finder_methods.rb +457 -261
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +167 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +153 -48
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +1019 -194
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +46 -150
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +450 -245
- data/lib/active_record/result.rb +104 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +120 -94
- data/lib/active_record/schema.rb +28 -18
- data/lib/active_record/schema_dumper.rb +141 -74
- data/lib/active_record/schema_migration.rb +50 -0
- data/lib/active_record/scoping/default.rb +64 -57
- data/lib/active_record/scoping/named.rb +93 -108
- data/lib/active_record/scoping.rb +73 -121
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +7 -5
- data/lib/active_record/statement_cache.rb +113 -0
- data/lib/active_record/store.rb +173 -15
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +313 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
- data/lib/active_record/timestamp.rb +42 -24
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +233 -105
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +7 -0
- data/lib/active_record/type/date_time.rb +7 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +63 -0
- data/lib/active_record/type/time.rb +20 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type.rb +72 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +33 -18
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +66 -0
- data/lib/active_record/validations/uniqueness.rb +128 -68
- data/lib/active_record/validations.rb +48 -40
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +71 -47
- data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
- data/lib/rails/generators/active_record/migration.rb +18 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +188 -134
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,96 +1,174 @@
|
|
1
|
-
require 'active_support/core_ext/array/wrap'
|
2
1
|
require 'active_support/core_ext/enumerable'
|
3
|
-
require 'active_support/core_ext/module/delegation'
|
4
|
-
require 'active_support/core_ext/object/blank'
|
5
2
|
require 'active_support/core_ext/string/conversions'
|
6
3
|
require 'active_support/core_ext/module/remove_method'
|
7
|
-
require '
|
4
|
+
require 'active_record/errors'
|
8
5
|
|
9
6
|
module ActiveRecord
|
7
|
+
class AssociationNotFoundError < ConfigurationError #:nodoc:
|
8
|
+
def initialize(record = nil, association_name = nil)
|
9
|
+
if record && association_name
|
10
|
+
super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
|
11
|
+
else
|
12
|
+
super("Association was not found.")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
10
17
|
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
11
|
-
def initialize(reflection, associated_class = nil)
|
12
|
-
|
18
|
+
def initialize(reflection = nil, associated_class = nil)
|
19
|
+
if reflection
|
20
|
+
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})")
|
21
|
+
else
|
22
|
+
super("Could not find the inverse association.")
|
23
|
+
end
|
13
24
|
end
|
14
25
|
end
|
15
26
|
|
16
27
|
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
|
17
|
-
def initialize(owner_class_name, reflection)
|
18
|
-
|
28
|
+
def initialize(owner_class_name = nil, reflection = nil)
|
29
|
+
if owner_class_name && reflection
|
30
|
+
super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class_name}")
|
31
|
+
else
|
32
|
+
super("Could not find the association.")
|
33
|
+
end
|
19
34
|
end
|
20
35
|
end
|
21
36
|
|
22
37
|
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
23
|
-
def initialize(owner_class_name, reflection, source_reflection)
|
24
|
-
|
38
|
+
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
39
|
+
if owner_class_name && reflection && source_reflection
|
40
|
+
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.")
|
41
|
+
else
|
42
|
+
super("Cannot have a has_many :through association.")
|
43
|
+
end
|
25
44
|
end
|
26
45
|
end
|
27
46
|
|
28
47
|
class HasManyThroughAssociationPolymorphicThroughError < ActiveRecordError #:nodoc:
|
29
|
-
def initialize(owner_class_name, reflection)
|
30
|
-
|
48
|
+
def initialize(owner_class_name = nil, reflection = nil)
|
49
|
+
if owner_class_name && reflection
|
50
|
+
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}'.")
|
51
|
+
else
|
52
|
+
super("Cannot have a has_many :through association.")
|
53
|
+
end
|
31
54
|
end
|
32
55
|
end
|
33
56
|
|
34
57
|
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
|
35
|
-
def initialize(owner_class_name, reflection, source_reflection)
|
36
|
-
|
58
|
+
def initialize(owner_class_name = nil, reflection = nil, source_reflection = nil)
|
59
|
+
if owner_class_name && reflection && source_reflection
|
60
|
+
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.")
|
61
|
+
else
|
62
|
+
super("Cannot have a has_many :through association.")
|
63
|
+
end
|
37
64
|
end
|
38
65
|
end
|
39
66
|
|
40
67
|
class HasOneThroughCantAssociateThroughCollection < ActiveRecordError #:nodoc:
|
41
|
-
def initialize(owner_class_name, reflection, through_reflection)
|
42
|
-
|
68
|
+
def initialize(owner_class_name = nil, reflection = nil, through_reflection = nil)
|
69
|
+
if owner_class_name && reflection && through_reflection
|
70
|
+
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.")
|
71
|
+
else
|
72
|
+
super("Cannot have a has_one :through association.")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class HasOneAssociationPolymorphicThroughError < ActiveRecordError #:nodoc:
|
78
|
+
def initialize(owner_class_name = nil, reflection = nil)
|
79
|
+
if owner_class_name && reflection
|
80
|
+
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}'.")
|
81
|
+
else
|
82
|
+
super("Cannot have a has_one :through association.")
|
83
|
+
end
|
43
84
|
end
|
44
85
|
end
|
45
86
|
|
46
87
|
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
|
47
|
-
def initialize(reflection)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
88
|
+
def initialize(reflection = nil)
|
89
|
+
if reflection
|
90
|
+
through_reflection = reflection.through_reflection
|
91
|
+
source_reflection_names = reflection.source_reflection_names
|
92
|
+
source_associations = reflection.through_reflection.klass._reflections.keys
|
93
|
+
super("Could not find the source association(s) #{source_reflection_names.collect(&:inspect).to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ', :locale => :en)} 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 ', :locale => :en)}?")
|
94
|
+
else
|
95
|
+
super("Could not find the source association(s).")
|
96
|
+
end
|
52
97
|
end
|
53
98
|
end
|
54
99
|
|
55
|
-
class
|
56
|
-
def initialize(owner, reflection)
|
57
|
-
|
100
|
+
class ThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError #:nodoc:
|
101
|
+
def initialize(owner = nil, reflection = nil)
|
102
|
+
if owner && reflection
|
103
|
+
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}.")
|
104
|
+
else
|
105
|
+
super("Cannot modify association.")
|
106
|
+
end
|
58
107
|
end
|
59
108
|
end
|
60
109
|
|
110
|
+
class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection #:nodoc:
|
111
|
+
end
|
112
|
+
|
113
|
+
class HasOneThroughCantAssociateThroughHasOneOrManyReflection < ThroughCantAssociateThroughHasOneOrManyReflection #:nodoc:
|
114
|
+
end
|
115
|
+
|
61
116
|
class HasManyThroughCantAssociateNewRecords < ActiveRecordError #:nodoc:
|
62
|
-
def initialize(owner, reflection)
|
63
|
-
|
117
|
+
def initialize(owner = nil, reflection = nil)
|
118
|
+
if owner && reflection
|
119
|
+
super("Cannot associate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to create the has_many :through record associating them.")
|
120
|
+
else
|
121
|
+
super("Cannot associate new records.")
|
122
|
+
end
|
64
123
|
end
|
65
124
|
end
|
66
125
|
|
67
126
|
class HasManyThroughCantDissociateNewRecords < ActiveRecordError #:nodoc:
|
68
|
-
def initialize(owner, reflection)
|
69
|
-
|
127
|
+
def initialize(owner = nil, reflection = nil)
|
128
|
+
if owner && reflection
|
129
|
+
super("Cannot dissociate new records through '#{owner.class.name}##{reflection.name}' on '#{reflection.source_reflection.class_name rescue nil}##{reflection.source_reflection.name rescue nil}'. Both records must have an id in order to delete the has_many :through record associating them.")
|
130
|
+
else
|
131
|
+
super("Cannot dissociate new records.")
|
132
|
+
end
|
70
133
|
end
|
71
134
|
end
|
72
135
|
|
73
|
-
class
|
74
|
-
def initialize(owner, reflection)
|
75
|
-
|
136
|
+
class ThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc:
|
137
|
+
def initialize(owner = nil, reflection = nil)
|
138
|
+
if owner && reflection
|
139
|
+
super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
|
140
|
+
else
|
141
|
+
super("Through nested associations are read-only.")
|
142
|
+
end
|
76
143
|
end
|
77
144
|
end
|
78
145
|
|
79
|
-
class
|
80
|
-
|
81
|
-
|
82
|
-
|
146
|
+
class HasManyThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly #:nodoc:
|
147
|
+
end
|
148
|
+
|
149
|
+
class HasOneThroughNestedAssociationsAreReadonly < ThroughNestedAssociationsAreReadonly #:nodoc:
|
83
150
|
end
|
84
151
|
|
85
|
-
|
86
|
-
|
87
|
-
|
152
|
+
# This error is raised when trying to eager load a polymorphic association using a JOIN.
|
153
|
+
# Eager loading polymorphic associations is only possible with
|
154
|
+
# {ActiveRecord::Relation#preload}[rdoc-ref:QueryMethods#preload].
|
155
|
+
class EagerLoadPolymorphicError < ActiveRecordError
|
156
|
+
def initialize(reflection = nil)
|
157
|
+
if reflection
|
158
|
+
super("Cannot eagerly load the polymorphic association #{reflection.name.inspect}")
|
159
|
+
else
|
160
|
+
super("Eager load polymorphic error.")
|
161
|
+
end
|
88
162
|
end
|
89
163
|
end
|
90
164
|
|
91
165
|
class ReadOnlyAssociation < ActiveRecordError #:nodoc:
|
92
|
-
def initialize(reflection)
|
93
|
-
|
166
|
+
def initialize(reflection = nil)
|
167
|
+
if reflection
|
168
|
+
super("Cannot add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.")
|
169
|
+
else
|
170
|
+
super("Read-only reflection error.")
|
171
|
+
end
|
94
172
|
end
|
95
173
|
end
|
96
174
|
|
@@ -98,8 +176,12 @@ module ActiveRecord
|
|
98
176
|
# (has_many, has_one) when there is at least 1 child associated instance.
|
99
177
|
# ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
|
100
178
|
class DeleteRestrictionError < ActiveRecordError #:nodoc:
|
101
|
-
def initialize(name)
|
102
|
-
|
179
|
+
def initialize(name = nil)
|
180
|
+
if name
|
181
|
+
super("Cannot delete record because of dependent #{name}")
|
182
|
+
else
|
183
|
+
super("Delete restriction error.")
|
184
|
+
end
|
103
185
|
end
|
104
186
|
end
|
105
187
|
|
@@ -110,19 +192,19 @@ module ActiveRecord
|
|
110
192
|
|
111
193
|
# These classes will be loaded when associations are created.
|
112
194
|
# So there is no need to eager load them.
|
113
|
-
autoload :Association
|
114
|
-
autoload :SingularAssociation
|
115
|
-
autoload :CollectionAssociation
|
116
|
-
autoload :
|
195
|
+
autoload :Association
|
196
|
+
autoload :SingularAssociation
|
197
|
+
autoload :CollectionAssociation
|
198
|
+
autoload :ForeignAssociation
|
199
|
+
autoload :CollectionProxy
|
117
200
|
|
118
|
-
autoload :BelongsToAssociation
|
119
|
-
autoload :BelongsToPolymorphicAssociation
|
120
|
-
autoload :
|
121
|
-
autoload :
|
122
|
-
autoload :
|
123
|
-
autoload :
|
124
|
-
autoload :
|
125
|
-
autoload :ThroughAssociation, 'active_record/associations/through_association'
|
201
|
+
autoload :BelongsToAssociation
|
202
|
+
autoload :BelongsToPolymorphicAssociation
|
203
|
+
autoload :HasManyAssociation
|
204
|
+
autoload :HasManyThroughAssociation
|
205
|
+
autoload :HasOneAssociation
|
206
|
+
autoload :HasOneThroughAssociation
|
207
|
+
autoload :ThroughAssociation
|
126
208
|
|
127
209
|
module Builder #:nodoc:
|
128
210
|
autoload :Association, 'active_record/associations/builder/association'
|
@@ -136,27 +218,20 @@ module ActiveRecord
|
|
136
218
|
end
|
137
219
|
|
138
220
|
eager_autoload do
|
139
|
-
autoload :Preloader
|
140
|
-
autoload :JoinDependency
|
141
|
-
autoload :AssociationScope
|
142
|
-
autoload :AliasTracker
|
143
|
-
autoload :JoinHelper, 'active_record/associations/join_helper'
|
221
|
+
autoload :Preloader
|
222
|
+
autoload :JoinDependency
|
223
|
+
autoload :AssociationScope
|
224
|
+
autoload :AliasTracker
|
144
225
|
end
|
145
226
|
|
146
|
-
# Clears out the association cache.
|
147
|
-
def clear_association_cache #:nodoc:
|
148
|
-
@association_cache.clear if persisted?
|
149
|
-
end
|
150
|
-
|
151
|
-
# :nodoc:
|
152
|
-
attr_reader :association_cache
|
153
|
-
|
154
227
|
# Returns the association instance for the given name, instantiating it if it doesn't already exist
|
155
228
|
def association(name) #:nodoc:
|
156
229
|
association = association_instance_get(name)
|
157
230
|
|
158
231
|
if association.nil?
|
159
|
-
reflection
|
232
|
+
unless reflection = self.class._reflect_on_association(name)
|
233
|
+
raise AssociationNotFoundError.new(self, name)
|
234
|
+
end
|
160
235
|
association = reflection.association_class.new(self, reflection)
|
161
236
|
association_instance_set(name, association)
|
162
237
|
end
|
@@ -164,10 +239,34 @@ module ActiveRecord
|
|
164
239
|
association
|
165
240
|
end
|
166
241
|
|
242
|
+
def association_cached?(name) # :nodoc
|
243
|
+
@association_cache.key?(name)
|
244
|
+
end
|
245
|
+
|
246
|
+
def initialize_dup(*) # :nodoc:
|
247
|
+
@association_cache = {}
|
248
|
+
super
|
249
|
+
end
|
250
|
+
|
251
|
+
def reload(*) # :nodoc:
|
252
|
+
clear_association_cache
|
253
|
+
super
|
254
|
+
end
|
255
|
+
|
167
256
|
private
|
168
|
-
#
|
257
|
+
# Clears out the association cache.
|
258
|
+
def clear_association_cache # :nodoc:
|
259
|
+
@association_cache.clear if persisted?
|
260
|
+
end
|
261
|
+
|
262
|
+
def init_internals # :nodoc:
|
263
|
+
@association_cache = {}
|
264
|
+
super
|
265
|
+
end
|
266
|
+
|
267
|
+
# Returns the specified association instance if it exists, nil otherwise.
|
169
268
|
def association_instance_get(name)
|
170
|
-
@association_cache[name
|
269
|
+
@association_cache[name]
|
171
270
|
end
|
172
271
|
|
173
272
|
# Set the specified association instance.
|
@@ -175,7 +274,7 @@ module ActiveRecord
|
|
175
274
|
@association_cache[name] = association
|
176
275
|
end
|
177
276
|
|
178
|
-
# Associations are a set of macro-like class methods for tying objects together through
|
277
|
+
# \Associations are a set of macro-like class methods for tying objects together through
|
179
278
|
# foreign keys. They express relationships like "Project has one Project Manager"
|
180
279
|
# or "Project belongs to a Portfolio". Each macro adds a number of methods to the
|
181
280
|
# class which are specialized according to the collection or association symbol and the
|
@@ -194,55 +293,36 @@ module ActiveRecord
|
|
194
293
|
# * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
|
195
294
|
# * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
|
196
295
|
# * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
|
197
|
-
# <tt>Project#milestones.delete(milestone), Project#milestones.
|
296
|
+
# <tt>Project#milestones.delete(milestone), Project#milestones.destroy(milestone), Project#milestones.find(milestone_id),</tt>
|
198
297
|
# <tt>Project#milestones.build, Project#milestones.create</tt>
|
199
298
|
# * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
|
200
|
-
# <tt>Project#categories.delete(category1)</tt>
|
201
|
-
#
|
202
|
-
# === Overriding generated methods
|
203
|
-
#
|
204
|
-
# Association methods are generated in a module that is included into the model class,
|
205
|
-
# which allows you to easily override with your own methods and call the original
|
206
|
-
# generated method with +super+. For example:
|
207
|
-
#
|
208
|
-
# class Car < ActiveRecord::Base
|
209
|
-
# belongs_to :owner
|
210
|
-
# belongs_to :old_owner
|
211
|
-
# def owner=(new_owner)
|
212
|
-
# self.old_owner = self.owner
|
213
|
-
# super
|
214
|
-
# end
|
215
|
-
# end
|
216
|
-
#
|
217
|
-
# If your model class is <tt>Project</tt>, the module is
|
218
|
-
# named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
|
219
|
-
# included in the model class immediately after the (anonymous) generated attributes methods
|
220
|
-
# module, meaning an association will override the methods for an attribute with the same name.
|
299
|
+
# <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
|
221
300
|
#
|
222
301
|
# === A word of warning
|
223
302
|
#
|
224
303
|
# Don't create associations that have the same name as instance methods of
|
225
|
-
#
|
304
|
+
# ActiveRecord::Base. Since the association adds a method with that name to
|
226
305
|
# its model, it will override the inherited method and break things.
|
227
306
|
# For instance, +attributes+ and +connection+ would be bad choices for association names.
|
228
307
|
#
|
229
308
|
# == Auto-generated methods
|
309
|
+
# See also Instance Public methods below for more details.
|
230
310
|
#
|
231
311
|
# === Singular associations (one-to-one)
|
232
312
|
# | | belongs_to |
|
233
313
|
# generated methods | belongs_to | :polymorphic | has_one
|
234
314
|
# ----------------------------------+------------+--------------+---------
|
235
|
-
# other
|
315
|
+
# other(force_reload=false) | X | X | X
|
236
316
|
# other=(other) | X | X | X
|
237
317
|
# build_other(attributes={}) | X | | X
|
238
318
|
# create_other(attributes={}) | X | | X
|
239
319
|
# create_other!(attributes={}) | X | | X
|
240
320
|
#
|
241
|
-
# ===Collection associations (one-to-many / many-to-many)
|
321
|
+
# === Collection associations (one-to-many / many-to-many)
|
242
322
|
# | | | has_many
|
243
323
|
# generated methods | habtm | has_many | :through
|
244
324
|
# ----------------------------------+-------+----------+----------
|
245
|
-
# others
|
325
|
+
# others(force_reload=false) | X | X | X
|
246
326
|
# others=(other,other,...) | X | X | X
|
247
327
|
# other_ids | X | X | X
|
248
328
|
# other_ids=(id,id,...) | X | X | X
|
@@ -255,27 +335,48 @@ module ActiveRecord
|
|
255
335
|
# others.size | X | X | X
|
256
336
|
# others.length | X | X | X
|
257
337
|
# others.count | X | X | X
|
258
|
-
# others.sum(args
|
338
|
+
# others.sum(*args) | X | X | X
|
259
339
|
# others.empty? | X | X | X
|
260
340
|
# others.clear | X | X | X
|
261
341
|
# others.delete(other,other,...) | X | X | X
|
262
342
|
# others.delete_all | X | X | X
|
343
|
+
# others.destroy(other,other,...) | X | X | X
|
263
344
|
# others.destroy_all | X | X | X
|
264
345
|
# others.find(*args) | X | X | X
|
265
346
|
# others.exists? | X | X | X
|
266
|
-
# others.
|
347
|
+
# others.distinct | X | X | X
|
267
348
|
# others.reset | X | X | X
|
268
349
|
#
|
350
|
+
# === Overriding generated methods
|
351
|
+
#
|
352
|
+
# Association methods are generated in a module that is included into the model class,
|
353
|
+
# which allows you to easily override with your own methods and call the original
|
354
|
+
# generated method with +super+. For example:
|
355
|
+
#
|
356
|
+
# class Car < ActiveRecord::Base
|
357
|
+
# belongs_to :owner
|
358
|
+
# belongs_to :old_owner
|
359
|
+
# def owner=(new_owner)
|
360
|
+
# self.old_owner = self.owner
|
361
|
+
# super
|
362
|
+
# end
|
363
|
+
# end
|
364
|
+
#
|
365
|
+
# If your model class is <tt>Project</tt>, the module is
|
366
|
+
# named <tt>Project::GeneratedAssociationMethods</tt>. The +GeneratedAssociationMethods+ module is
|
367
|
+
# included in the model class immediately after the (anonymous) generated attributes methods
|
368
|
+
# module, meaning an association will override the methods for an attribute with the same name.
|
369
|
+
#
|
269
370
|
# == Cardinality and associations
|
270
371
|
#
|
271
372
|
# Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
|
272
373
|
# relationships between models. Each model uses an association to describe its role in
|
273
|
-
# the relation. The
|
374
|
+
# the relation. The #belongs_to association is always used in the model that has
|
274
375
|
# the foreign key.
|
275
376
|
#
|
276
377
|
# === One-to-one
|
277
378
|
#
|
278
|
-
# Use
|
379
|
+
# Use #has_one in the base, and #belongs_to in the associated model.
|
279
380
|
#
|
280
381
|
# class Employee < ActiveRecord::Base
|
281
382
|
# has_one :office
|
@@ -286,7 +387,7 @@ module ActiveRecord
|
|
286
387
|
#
|
287
388
|
# === One-to-many
|
288
389
|
#
|
289
|
-
# Use
|
390
|
+
# Use #has_many in the base, and #belongs_to in the associated model.
|
290
391
|
#
|
291
392
|
# class Manager < ActiveRecord::Base
|
292
393
|
# has_many :employees
|
@@ -299,7 +400,7 @@ module ActiveRecord
|
|
299
400
|
#
|
300
401
|
# There are two ways to build a many-to-many relationship.
|
301
402
|
#
|
302
|
-
# The first way uses a
|
403
|
+
# The first way uses a #has_many association with the <tt>:through</tt> option and a join model, so
|
303
404
|
# there are two stages of associations.
|
304
405
|
#
|
305
406
|
# class Assignment < ActiveRecord::Base
|
@@ -308,14 +409,14 @@ module ActiveRecord
|
|
308
409
|
# end
|
309
410
|
# class Programmer < ActiveRecord::Base
|
310
411
|
# has_many :assignments
|
311
|
-
# has_many :projects, :
|
412
|
+
# has_many :projects, through: :assignments
|
312
413
|
# end
|
313
414
|
# class Project < ActiveRecord::Base
|
314
415
|
# has_many :assignments
|
315
|
-
# has_many :programmers, :
|
416
|
+
# has_many :programmers, through: :assignments
|
316
417
|
# end
|
317
418
|
#
|
318
|
-
# For the second way, use
|
419
|
+
# For the second way, use #has_and_belongs_to_many in both models. This requires a join table
|
319
420
|
# that has no corresponding model or primary key.
|
320
421
|
#
|
321
422
|
# class Programmer < ActiveRecord::Base
|
@@ -327,13 +428,13 @@ module ActiveRecord
|
|
327
428
|
#
|
328
429
|
# Choosing which way to build a many-to-many relationship is not always simple.
|
329
430
|
# If you need to work with the relationship model as its own entity,
|
330
|
-
# use <tt
|
431
|
+
# use #has_many <tt>:through</tt>. Use #has_and_belongs_to_many when working with legacy schemas or when
|
331
432
|
# you never work directly with the relationship itself.
|
332
433
|
#
|
333
|
-
# == Is it a
|
434
|
+
# == Is it a #belongs_to or #has_one association?
|
334
435
|
#
|
335
436
|
# Both express a 1-1 relationship. The difference is mostly where to place the foreign
|
336
|
-
# key, which goes on the table for the class declaring the
|
437
|
+
# key, which goes on the table for the class declaring the #belongs_to relationship.
|
337
438
|
#
|
338
439
|
# class User < ActiveRecord::Base
|
339
440
|
# # I reference an account.
|
@@ -348,14 +449,14 @@ module ActiveRecord
|
|
348
449
|
# The tables for these classes could look something like:
|
349
450
|
#
|
350
451
|
# CREATE TABLE users (
|
351
|
-
# id int
|
352
|
-
# account_id int
|
452
|
+
# id int NOT NULL auto_increment,
|
453
|
+
# account_id int default NULL,
|
353
454
|
# name varchar default NULL,
|
354
455
|
# PRIMARY KEY (id)
|
355
456
|
# )
|
356
457
|
#
|
357
458
|
# CREATE TABLE accounts (
|
358
|
-
# id int
|
459
|
+
# id int NOT NULL auto_increment,
|
359
460
|
# name varchar default NULL,
|
360
461
|
# PRIMARY KEY (id)
|
361
462
|
# )
|
@@ -366,49 +467,74 @@ module ActiveRecord
|
|
366
467
|
# there is some special behavior you should be aware of, mostly involving the saving of
|
367
468
|
# associated objects.
|
368
469
|
#
|
369
|
-
# You can set the
|
370
|
-
#
|
470
|
+
# You can set the <tt>:autosave</tt> option on a #has_one, #belongs_to,
|
471
|
+
# #has_many, or #has_and_belongs_to_many association. Setting it
|
371
472
|
# to +true+ will _always_ save the members, whereas setting it to +false+ will
|
372
|
-
# _never_ save the members. More details about
|
373
|
-
#
|
473
|
+
# _never_ save the members. More details about <tt>:autosave</tt> option is available at
|
474
|
+
# AutosaveAssociation.
|
374
475
|
#
|
375
476
|
# === One-to-one associations
|
376
477
|
#
|
377
|
-
# * Assigning an object to a
|
478
|
+
# * Assigning an object to a #has_one association automatically saves that object and
|
378
479
|
# the object being replaced (if there is one), in order to update their foreign
|
379
480
|
# keys - except if the parent object is unsaved (<tt>new_record? == true</tt>).
|
380
481
|
# * If either of these saves fail (due to one of the objects being invalid), an
|
381
|
-
#
|
482
|
+
# ActiveRecord::RecordNotSaved exception is raised and the assignment is
|
382
483
|
# cancelled.
|
383
|
-
# * If you wish to assign an object to a
|
384
|
-
# use the <tt
|
484
|
+
# * If you wish to assign an object to a #has_one association without saving it,
|
485
|
+
# use the <tt>#build_association</tt> method (documented below). The object being
|
385
486
|
# replaced will still be saved to update its foreign key.
|
386
|
-
# * Assigning an object to a
|
487
|
+
# * Assigning an object to a #belongs_to association does not save the object, since
|
387
488
|
# the foreign key field belongs on the parent. It does not save the parent either.
|
388
489
|
#
|
389
490
|
# === Collections
|
390
491
|
#
|
391
|
-
# * Adding an object to a collection (
|
492
|
+
# * Adding an object to a collection (#has_many or #has_and_belongs_to_many) automatically
|
392
493
|
# saves that object, except if the parent object (the owner of the collection) is not yet
|
393
494
|
# stored in the database.
|
394
495
|
# * If saving any of the objects being added to a collection (via <tt>push</tt> or similar)
|
395
496
|
# fails, then <tt>push</tt> returns +false+.
|
396
497
|
# * If saving fails while replacing the collection (via <tt>association=</tt>), an
|
397
|
-
#
|
498
|
+
# ActiveRecord::RecordNotSaved exception is raised and the assignment is
|
398
499
|
# cancelled.
|
399
500
|
# * You can add an object to a collection without automatically saving it by using the
|
400
501
|
# <tt>collection.build</tt> method (documented below).
|
401
502
|
# * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically
|
402
503
|
# saved when the parent is saved.
|
403
504
|
#
|
404
|
-
#
|
505
|
+
# == Customizing the query
|
506
|
+
#
|
507
|
+
# \Associations are built from <tt>Relation</tt> objects, and you can use the Relation syntax
|
508
|
+
# to customize them. For example, to add a condition:
|
509
|
+
#
|
510
|
+
# class Blog < ActiveRecord::Base
|
511
|
+
# has_many :published_posts, -> { where(published: true) }, class_name: 'Post'
|
512
|
+
# end
|
513
|
+
#
|
514
|
+
# Inside the <tt>-> { ... }</tt> block you can use all of the usual Relation methods.
|
515
|
+
#
|
516
|
+
# === Accessing the owner object
|
517
|
+
#
|
518
|
+
# Sometimes it is useful to have access to the owner object when building the query. The owner
|
519
|
+
# is passed as a parameter to the block. For example, the following association would find all
|
520
|
+
# events that occur on the user's birthday:
|
521
|
+
#
|
522
|
+
# class User < ActiveRecord::Base
|
523
|
+
# has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event'
|
524
|
+
# end
|
525
|
+
#
|
526
|
+
# Note: Joining, eager loading and preloading of these associations is not fully possible.
|
527
|
+
# These operations happen before instance creation and the scope will be called with a +nil+ argument.
|
528
|
+
# This can lead to unexpected behavior and is deprecated.
|
529
|
+
#
|
530
|
+
# == Association callbacks
|
405
531
|
#
|
406
532
|
# Similar to the normal callbacks that hook into the life cycle of an Active Record object,
|
407
533
|
# you can also define callbacks that get triggered when you add an object to or remove an
|
408
534
|
# object from an association collection.
|
409
535
|
#
|
410
536
|
# class Project
|
411
|
-
# has_and_belongs_to_many :developers, :
|
537
|
+
# has_and_belongs_to_many :developers, after_add: :evaluate_velocity
|
412
538
|
#
|
413
539
|
# def evaluate_velocity(developer)
|
414
540
|
# ...
|
@@ -419,16 +545,18 @@ module ActiveRecord
|
|
419
545
|
#
|
420
546
|
# class Project
|
421
547
|
# has_and_belongs_to_many :developers,
|
422
|
-
# :
|
548
|
+
# after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
|
423
549
|
# end
|
424
550
|
#
|
425
551
|
# Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
|
426
552
|
#
|
427
|
-
#
|
428
|
-
# added to the collection.
|
429
|
-
#
|
553
|
+
# If any of the +before_add+ callbacks throw an exception, the object will not be
|
554
|
+
# added to the collection.
|
555
|
+
#
|
556
|
+
# Similarly, if any of the +before_remove+ callbacks throw an exception, the object
|
557
|
+
# will not be removed from the collection.
|
430
558
|
#
|
431
|
-
#
|
559
|
+
# == Association extensions
|
432
560
|
#
|
433
561
|
# The proxy objects that control the access to associations can be extended through anonymous
|
434
562
|
# modules. This is especially beneficial for adding new finders, creators, and other
|
@@ -438,7 +566,7 @@ module ActiveRecord
|
|
438
566
|
# has_many :people do
|
439
567
|
# def find_or_create_by_name(name)
|
440
568
|
# first_name, last_name = name.split(" ", 2)
|
441
|
-
#
|
569
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
442
570
|
# end
|
443
571
|
# end
|
444
572
|
# end
|
@@ -453,25 +581,16 @@ module ActiveRecord
|
|
453
581
|
# module FindOrCreateByNameExtension
|
454
582
|
# def find_or_create_by_name(name)
|
455
583
|
# first_name, last_name = name.split(" ", 2)
|
456
|
-
#
|
584
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
457
585
|
# end
|
458
586
|
# end
|
459
587
|
#
|
460
588
|
# class Account < ActiveRecord::Base
|
461
|
-
# has_many :people,
|
589
|
+
# has_many :people, -> { extending FindOrCreateByNameExtension }
|
462
590
|
# end
|
463
591
|
#
|
464
592
|
# class Company < ActiveRecord::Base
|
465
|
-
# has_many :people,
|
466
|
-
# end
|
467
|
-
#
|
468
|
-
# If you need to use multiple named extension modules, you can specify an array of modules
|
469
|
-
# with the <tt>:extend</tt> option.
|
470
|
-
# In the case of name conflicts between methods in the modules, methods in modules later
|
471
|
-
# in the array supercede those earlier in the array.
|
472
|
-
#
|
473
|
-
# class Account < ActiveRecord::Base
|
474
|
-
# has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
|
593
|
+
# has_many :people, -> { extending FindOrCreateByNameExtension }
|
475
594
|
# end
|
476
595
|
#
|
477
596
|
# Some extensions can only be made to work with knowledge of the association's internals.
|
@@ -480,8 +599,8 @@ module ActiveRecord
|
|
480
599
|
#
|
481
600
|
# * <tt>record.association(:items).owner</tt> - Returns the object the association is part of.
|
482
601
|
# * <tt>record.association(:items).reflection</tt> - Returns the reflection object that describes the association.
|
483
|
-
# * <tt>record.association(:items).target</tt> - Returns the associated object for
|
484
|
-
# the collection of associated objects for
|
602
|
+
# * <tt>record.association(:items).target</tt> - Returns the associated object for #belongs_to and #has_one, or
|
603
|
+
# the collection of associated objects for #has_many and #has_and_belongs_to_many.
|
485
604
|
#
|
486
605
|
# However, inside the actual extension code, you will not have access to the <tt>record</tt> as
|
487
606
|
# above. In this case, you can access <tt>proxy_association</tt>. For example,
|
@@ -489,16 +608,16 @@ module ActiveRecord
|
|
489
608
|
# the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside
|
490
609
|
# association extensions.
|
491
610
|
#
|
492
|
-
#
|
611
|
+
# == Association Join Models
|
493
612
|
#
|
494
613
|
# Has Many associations can be configured with the <tt>:through</tt> option to use an
|
495
614
|
# explicit join model to retrieve the data. This operates similarly to a
|
496
|
-
#
|
615
|
+
# #has_and_belongs_to_many association. The advantage is that you're able to add validations,
|
497
616
|
# callbacks, and extra attributes on the join model. Consider the following schema:
|
498
617
|
#
|
499
618
|
# class Author < ActiveRecord::Base
|
500
619
|
# has_many :authorships
|
501
|
-
# has_many :books, :
|
620
|
+
# has_many :books, through: :authorships
|
502
621
|
# end
|
503
622
|
#
|
504
623
|
# class Authorship < ActiveRecord::Base
|
@@ -510,11 +629,11 @@ module ActiveRecord
|
|
510
629
|
# @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to
|
511
630
|
# @author.books # selects all books by using the Authorship join model
|
512
631
|
#
|
513
|
-
# You can also go through a
|
632
|
+
# You can also go through a #has_many association on the join model:
|
514
633
|
#
|
515
634
|
# class Firm < ActiveRecord::Base
|
516
635
|
# has_many :clients
|
517
|
-
# has_many :invoices, :
|
636
|
+
# has_many :invoices, through: :clients
|
518
637
|
# end
|
519
638
|
#
|
520
639
|
# class Client < ActiveRecord::Base
|
@@ -527,14 +646,14 @@ module ActiveRecord
|
|
527
646
|
# end
|
528
647
|
#
|
529
648
|
# @firm = Firm.first
|
530
|
-
# @firm.clients.
|
531
|
-
# @firm.invoices
|
649
|
+
# @firm.clients.flat_map { |c| c.invoices } # select all invoices for all clients of the firm
|
650
|
+
# @firm.invoices # selects all invoices by going through the Client join model
|
532
651
|
#
|
533
|
-
# Similarly you can go through a
|
652
|
+
# Similarly you can go through a #has_one association on the join model:
|
534
653
|
#
|
535
654
|
# class Group < ActiveRecord::Base
|
536
655
|
# has_many :users
|
537
|
-
# has_many :avatars, :
|
656
|
+
# has_many :avatars, through: :users
|
538
657
|
# end
|
539
658
|
#
|
540
659
|
# class User < ActiveRecord::Base
|
@@ -547,41 +666,63 @@ module ActiveRecord
|
|
547
666
|
# end
|
548
667
|
#
|
549
668
|
# @group = Group.first
|
550
|
-
# @group.users.collect { |u| u.avatar }.
|
669
|
+
# @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
|
551
670
|
# @group.avatars # selects all avatars by going through the User join model.
|
552
671
|
#
|
553
|
-
# An important caveat with going through
|
672
|
+
# An important caveat with going through #has_one or #has_many associations on the
|
554
673
|
# join model is that these associations are *read-only*. For example, the following
|
555
674
|
# would not work following the previous example:
|
556
675
|
#
|
557
676
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
558
677
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
559
678
|
#
|
560
|
-
#
|
561
|
-
#
|
562
|
-
#
|
679
|
+
# == Setting Inverses
|
680
|
+
#
|
681
|
+
# If you are using a #belongs_to on the join model, it is a good idea to set the
|
682
|
+
# <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
|
683
|
+
# works correctly (where <tt>tags</tt> is a #has_many <tt>:through</tt> association):
|
563
684
|
#
|
564
685
|
# @post = Post.first
|
565
|
-
# @tag = @post.tags.build :
|
686
|
+
# @tag = @post.tags.build name: "ruby"
|
566
687
|
# @tag.save
|
567
688
|
#
|
568
|
-
# The last line ought to save the through record (a <tt>
|
689
|
+
# The last line ought to save the through record (a <tt>Tagging</tt>). This will only work if the
|
569
690
|
# <tt>:inverse_of</tt> is set:
|
570
691
|
#
|
571
|
-
# class
|
692
|
+
# class Tagging < ActiveRecord::Base
|
572
693
|
# belongs_to :post
|
573
|
-
# belongs_to :tag, :
|
694
|
+
# belongs_to :tag, inverse_of: :taggings
|
574
695
|
# end
|
575
696
|
#
|
576
|
-
#
|
697
|
+
# If you do not set the <tt>:inverse_of</tt> record, the association will
|
698
|
+
# do its best to match itself up with the correct inverse. Automatic
|
699
|
+
# inverse detection only works on #has_many, #has_one, and
|
700
|
+
# #belongs_to associations.
|
701
|
+
#
|
702
|
+
# Extra options on the associations, as defined in the
|
703
|
+
# <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will
|
704
|
+
# also prevent the association's inverse from being found automatically.
|
705
|
+
#
|
706
|
+
# The automatic guessing of the inverse association uses a heuristic based
|
707
|
+
# on the name of the class, so it may not work for all associations,
|
708
|
+
# especially the ones with non-standard names.
|
709
|
+
#
|
710
|
+
# You can turn off the automatic detection of inverse associations by setting
|
711
|
+
# the <tt>:inverse_of</tt> option to <tt>false</tt> like so:
|
712
|
+
#
|
713
|
+
# class Tagging < ActiveRecord::Base
|
714
|
+
# belongs_to :tag, inverse_of: false
|
715
|
+
# end
|
716
|
+
#
|
717
|
+
# == Nested \Associations
|
577
718
|
#
|
578
719
|
# You can actually specify *any* association with the <tt>:through</tt> option, including an
|
579
720
|
# association which has a <tt>:through</tt> option itself. For example:
|
580
721
|
#
|
581
722
|
# class Author < ActiveRecord::Base
|
582
723
|
# has_many :posts
|
583
|
-
# has_many :comments, :
|
584
|
-
# has_many :commenters, :
|
724
|
+
# has_many :comments, through: :posts
|
725
|
+
# has_many :commenters, through: :comments
|
585
726
|
# end
|
586
727
|
#
|
587
728
|
# class Post < ActiveRecord::Base
|
@@ -599,35 +740,35 @@ module ActiveRecord
|
|
599
740
|
#
|
600
741
|
# class Author < ActiveRecord::Base
|
601
742
|
# has_many :posts
|
602
|
-
# has_many :commenters, :
|
743
|
+
# has_many :commenters, through: :posts
|
603
744
|
# end
|
604
745
|
#
|
605
746
|
# class Post < ActiveRecord::Base
|
606
747
|
# has_many :comments
|
607
|
-
# has_many :commenters, :
|
748
|
+
# has_many :commenters, through: :comments
|
608
749
|
# end
|
609
750
|
#
|
610
751
|
# class Comment < ActiveRecord::Base
|
611
752
|
# belongs_to :commenter
|
612
753
|
# end
|
613
754
|
#
|
614
|
-
# When using nested association, you will not be able to modify the association because there
|
755
|
+
# When using a nested association, you will not be able to modify the association because there
|
615
756
|
# is not enough information to know what modification to make. For example, if you tried to
|
616
757
|
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
|
617
758
|
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
|
618
759
|
#
|
619
|
-
#
|
760
|
+
# == Polymorphic \Associations
|
620
761
|
#
|
621
762
|
# Polymorphic associations on models are not restricted on what types of models they
|
622
|
-
# can be associated with. Rather, they specify an interface that a
|
763
|
+
# can be associated with. Rather, they specify an interface that a #has_many association
|
623
764
|
# must adhere to.
|
624
765
|
#
|
625
766
|
# class Asset < ActiveRecord::Base
|
626
|
-
# belongs_to :attachable, :
|
767
|
+
# belongs_to :attachable, polymorphic: true
|
627
768
|
# end
|
628
769
|
#
|
629
770
|
# class Post < ActiveRecord::Base
|
630
|
-
# has_many :assets, :
|
771
|
+
# has_many :assets, as: :attachable # The :as option specifies the polymorphic interface to use.
|
631
772
|
# end
|
632
773
|
#
|
633
774
|
# @asset.attachable = @post
|
@@ -643,17 +784,20 @@ module ActiveRecord
|
|
643
784
|
# and member posts that use the posts table for STI. In this case, there must be a +type+
|
644
785
|
# column in the posts table.
|
645
786
|
#
|
787
|
+
# Note: The <tt>attachable_type=</tt> method is being called when assigning an +attachable+.
|
788
|
+
# The +class_name+ of the +attachable+ is passed as a String.
|
789
|
+
#
|
646
790
|
# class Asset < ActiveRecord::Base
|
647
|
-
# belongs_to :attachable, :
|
791
|
+
# belongs_to :attachable, polymorphic: true
|
648
792
|
#
|
649
|
-
# def attachable_type=(
|
650
|
-
# super(
|
793
|
+
# def attachable_type=(class_name)
|
794
|
+
# super(class_name.constantize.base_class.to_s)
|
651
795
|
# end
|
652
796
|
# end
|
653
797
|
#
|
654
798
|
# class Post < ActiveRecord::Base
|
655
|
-
# # because we store "Post" in attachable_type now :
|
656
|
-
# has_many :assets, :
|
799
|
+
# # because we store "Post" in attachable_type now dependent: :destroy will work
|
800
|
+
# has_many :assets, as: :attachable, dependent: :destroy
|
657
801
|
# end
|
658
802
|
#
|
659
803
|
# class GuestPost < Post
|
@@ -678,9 +822,9 @@ module ActiveRecord
|
|
678
822
|
# == Eager loading of associations
|
679
823
|
#
|
680
824
|
# Eager loading is a way to find objects of a certain class and a number of named associations.
|
681
|
-
#
|
825
|
+
# It is one of the easiest ways to prevent the dreaded N+1 problem in which fetching 100
|
682
826
|
# posts that each need to display their author triggers 101 database queries. Through the
|
683
|
-
# use of eager loading, the
|
827
|
+
# use of eager loading, the number of queries will be reduced from 101 to 2.
|
684
828
|
#
|
685
829
|
# class Post < ActiveRecord::Base
|
686
830
|
# belongs_to :author
|
@@ -700,7 +844,7 @@ module ActiveRecord
|
|
700
844
|
#
|
701
845
|
# Post.includes(:author).each do |post|
|
702
846
|
#
|
703
|
-
# This references the name of the
|
847
|
+
# This references the name of the #belongs_to association that also used the <tt>:author</tt>
|
704
848
|
# symbol. After loading the posts, find will collect the +author_id+ from each one and load
|
705
849
|
# all the referenced authors with one query. Doing so will cut down the number of queries
|
706
850
|
# from 201 to 102.
|
@@ -710,16 +854,16 @@ module ActiveRecord
|
|
710
854
|
# Post.includes(:author, :comments).each do |post|
|
711
855
|
#
|
712
856
|
# This will load all comments with a single query. This reduces the total number of queries
|
713
|
-
# to 3.
|
714
|
-
# named (except if some of the associations are polymorphic
|
857
|
+
# to 3. In general, the number of queries will be 1 plus the number of associations
|
858
|
+
# named (except if some of the associations are polymorphic #belongs_to - see below).
|
715
859
|
#
|
716
860
|
# To include a deep hierarchy of associations, use a hash:
|
717
861
|
#
|
718
|
-
# Post.includes(:author, {:
|
862
|
+
# Post.includes(:author, { comments: { author: :gravatar } }).each do |post|
|
719
863
|
#
|
720
|
-
#
|
721
|
-
# You can mix and match
|
722
|
-
# associations you want to load.
|
864
|
+
# The above code will load all the comments and all of their associated
|
865
|
+
# authors and gravatars. You can mix and match any combination of symbols,
|
866
|
+
# arrays, and hashes to retrieve the associations you want to load.
|
723
867
|
#
|
724
868
|
# All of this power shouldn't fool you into thinking that you can pull out huge amounts
|
725
869
|
# of data with no performance penalty just because you've reduced the number of queries.
|
@@ -728,10 +872,10 @@ module ActiveRecord
|
|
728
872
|
# cut down on the number of queries in a situation as the one described above.
|
729
873
|
#
|
730
874
|
# Since only one table is loaded at a time, conditions or orders cannot reference tables
|
731
|
-
# other than the main one. If this is the case Active Record falls back to the previously
|
732
|
-
# used LEFT OUTER JOIN based strategy. For example
|
875
|
+
# other than the main one. If this is the case, Active Record falls back to the previously
|
876
|
+
# used LEFT OUTER JOIN based strategy. For example:
|
733
877
|
#
|
734
|
-
# Post.includes([:author, :comments]).where(['comments.approved = ?', true])
|
878
|
+
# Post.includes([:author, :comments]).where(['comments.approved = ?', true])
|
735
879
|
#
|
736
880
|
# This will result in a single SQL query with joins along the lines of:
|
737
881
|
# <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
|
@@ -739,14 +883,19 @@ module ActiveRecord
|
|
739
883
|
# like this can have unintended consequences.
|
740
884
|
# In the above example posts with no approved comments are not returned at all, because
|
741
885
|
# the conditions apply to the SQL statement as a whole and not just to the association.
|
886
|
+
#
|
742
887
|
# You must disambiguate column references for this fallback to happen, for example
|
743
|
-
# <tt
|
888
|
+
# <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
|
889
|
+
#
|
890
|
+
# If you want to load all posts (including posts with no approved comments) then write
|
891
|
+
# your own LEFT OUTER JOIN query using ON
|
892
|
+
#
|
893
|
+
# Post.joins("LEFT OUTER JOIN comments ON comments.post_id = posts.id AND comments.approved = '1'")
|
744
894
|
#
|
745
|
-
#
|
746
|
-
# to include an association which has conditions defined on it:
|
895
|
+
# In this case it is usually more natural to include an association which has conditions defined on it:
|
747
896
|
#
|
748
897
|
# class Post < ActiveRecord::Base
|
749
|
-
# has_many :approved_comments, :
|
898
|
+
# has_many :approved_comments, -> { where(approved: true) }, class_name: 'Comment'
|
750
899
|
# end
|
751
900
|
#
|
752
901
|
# Post.includes(:approved_comments)
|
@@ -758,18 +907,15 @@ module ActiveRecord
|
|
758
907
|
# returning all the associated objects:
|
759
908
|
#
|
760
909
|
# class Picture < ActiveRecord::Base
|
761
|
-
# has_many :most_recent_comments,
|
910
|
+
# has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment'
|
762
911
|
# end
|
763
912
|
#
|
764
913
|
# Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
|
765
914
|
#
|
766
|
-
# When eager loaded, conditions are interpolated in the context of the model class, not
|
767
|
-
# the model instance. Conditions are lazily interpolated before the actual model exists.
|
768
|
-
#
|
769
915
|
# Eager loading is supported with polymorphic associations.
|
770
916
|
#
|
771
917
|
# class Address < ActiveRecord::Base
|
772
|
-
# belongs_to :addressable, :
|
918
|
+
# belongs_to :addressable, polymorphic: true
|
773
919
|
# end
|
774
920
|
#
|
775
921
|
# A call that tries to eager load the addressable model
|
@@ -803,10 +949,10 @@ module ActiveRecord
|
|
803
949
|
#
|
804
950
|
# TreeMixin.joins(:children)
|
805
951
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
806
|
-
# TreeMixin.joins(:
|
952
|
+
# TreeMixin.joins(children: :parent)
|
807
953
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
808
954
|
# INNER JOIN parents_mixins ...
|
809
|
-
# TreeMixin.joins(:
|
955
|
+
# TreeMixin.joins(children: {parent: :children})
|
810
956
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
811
957
|
# INNER JOIN parents_mixins ...
|
812
958
|
# INNER JOIN mixins childrens_mixins_2
|
@@ -815,15 +961,15 @@ module ActiveRecord
|
|
815
961
|
#
|
816
962
|
# Post.joins(:categories)
|
817
963
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
818
|
-
# Post.joins(:
|
964
|
+
# Post.joins(categories: :posts)
|
819
965
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
820
966
|
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
821
|
-
# Post.joins(:
|
967
|
+
# Post.joins(categories: {posts: :categories})
|
822
968
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
823
969
|
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
824
970
|
# INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
|
825
971
|
#
|
826
|
-
# If you wish to specify your own custom joins using
|
972
|
+
# If you wish to specify your own custom joins using ActiveRecord::QueryMethods#joins method, those table
|
827
973
|
# names will take precedence over the eager associations:
|
828
974
|
#
|
829
975
|
# Post.joins(:comments).joins("inner join comments ...")
|
@@ -843,8 +989,8 @@ module ActiveRecord
|
|
843
989
|
# module MyApplication
|
844
990
|
# module Business
|
845
991
|
# class Firm < ActiveRecord::Base
|
846
|
-
#
|
847
|
-
#
|
992
|
+
# has_many :clients
|
993
|
+
# end
|
848
994
|
#
|
849
995
|
# class Client < ActiveRecord::Base; end
|
850
996
|
# end
|
@@ -862,7 +1008,7 @@ module ActiveRecord
|
|
862
1008
|
#
|
863
1009
|
# module Billing
|
864
1010
|
# class Account < ActiveRecord::Base
|
865
|
-
# belongs_to :firm, :
|
1011
|
+
# belongs_to :firm, class_name: "MyApplication::Business::Firm"
|
866
1012
|
# end
|
867
1013
|
# end
|
868
1014
|
# end
|
@@ -888,76 +1034,79 @@ module ActiveRecord
|
|
888
1034
|
# The +traps+ association on +Dungeon+ and the +dungeon+ association on +Trap+ are
|
889
1035
|
# the inverse of each other and the inverse of the +dungeon+ association on +EvilWizard+
|
890
1036
|
# is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default,
|
891
|
-
# Active Record
|
892
|
-
#
|
1037
|
+
# Active Record can guess the inverse of the association based on the name
|
1038
|
+
# of the class. The result is the following:
|
893
1039
|
#
|
894
1040
|
# d = Dungeon.first
|
895
1041
|
# t = d.traps.first
|
896
|
-
# d.
|
897
|
-
# d.level = 10
|
898
|
-
# d.level == t.dungeon.level # => false
|
1042
|
+
# d.object_id == t.dungeon.object_id # => true
|
899
1043
|
#
|
900
1044
|
# The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to
|
901
|
-
# the same
|
902
|
-
#
|
903
|
-
# Active Record about inverse relationships and it will optimise object loading. For
|
904
|
-
# example, if we changed our model definitions to:
|
1045
|
+
# the same in-memory instance since the association matches the name of the class.
|
1046
|
+
# The result would be the same if we added +:inverse_of+ to our model definitions:
|
905
1047
|
#
|
906
1048
|
# class Dungeon < ActiveRecord::Base
|
907
|
-
# has_many :traps, :
|
908
|
-
# has_one :evil_wizard, :
|
1049
|
+
# has_many :traps, inverse_of: :dungeon
|
1050
|
+
# has_one :evil_wizard, inverse_of: :dungeon
|
909
1051
|
# end
|
910
1052
|
#
|
911
1053
|
# class Trap < ActiveRecord::Base
|
912
|
-
# belongs_to :dungeon, :
|
1054
|
+
# belongs_to :dungeon, inverse_of: :traps
|
913
1055
|
# end
|
914
1056
|
#
|
915
1057
|
# class EvilWizard < ActiveRecord::Base
|
916
|
-
# belongs_to :dungeon, :
|
1058
|
+
# belongs_to :dungeon, inverse_of: :evil_wizard
|
917
1059
|
# end
|
918
1060
|
#
|
919
|
-
# Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same
|
920
|
-
# in-memory instance and our final <tt>d.level == t.dungeon.level</tt> will return +true+.
|
921
|
-
#
|
922
1061
|
# There are limitations to <tt>:inverse_of</tt> support:
|
923
1062
|
#
|
924
1063
|
# * does not work with <tt>:through</tt> associations.
|
925
1064
|
# * does not work with <tt>:polymorphic</tt> associations.
|
926
|
-
# * for
|
1065
|
+
# * for #belongs_to associations #has_many inverse associations are ignored.
|
1066
|
+
#
|
1067
|
+
# For more information, see the documentation for the +:inverse_of+ option.
|
927
1068
|
#
|
928
1069
|
# == Deleting from associations
|
929
1070
|
#
|
930
1071
|
# === Dependent associations
|
931
1072
|
#
|
932
|
-
#
|
1073
|
+
# #has_many, #has_one and #belongs_to associations support the <tt>:dependent</tt> option.
|
933
1074
|
# This allows you to specify that associated records should be deleted when the owner is
|
934
1075
|
# deleted.
|
935
1076
|
#
|
936
1077
|
# For example:
|
937
1078
|
#
|
938
1079
|
# class Author
|
939
|
-
# has_many :posts, :
|
1080
|
+
# has_many :posts, dependent: :destroy
|
940
1081
|
# end
|
941
1082
|
# Author.find(1).destroy # => Will destroy all of the author's posts, too
|
942
1083
|
#
|
943
1084
|
# The <tt>:dependent</tt> option can have different values which specify how the deletion
|
944
1085
|
# is done. For more information, see the documentation for this option on the different
|
945
|
-
# specific association types.
|
1086
|
+
# specific association types. When no option is given, the behavior is to do nothing
|
1087
|
+
# with the associated records when destroying a record.
|
1088
|
+
#
|
1089
|
+
# Note that <tt>:dependent</tt> is implemented using Rails' callback
|
1090
|
+
# system, which works by processing callbacks in order. Therefore, other
|
1091
|
+
# callbacks declared either before or after the <tt>:dependent</tt> option
|
1092
|
+
# can affect what it does.
|
1093
|
+
#
|
1094
|
+
# Note that <tt>:dependent</tt> option is ignored for #has_one <tt>:through</tt> associations.
|
946
1095
|
#
|
947
1096
|
# === Delete or destroy?
|
948
1097
|
#
|
949
|
-
#
|
1098
|
+
# #has_many and #has_and_belongs_to_many associations have the methods <tt>destroy</tt>,
|
950
1099
|
# <tt>delete</tt>, <tt>destroy_all</tt> and <tt>delete_all</tt>.
|
951
1100
|
#
|
952
|
-
# For
|
1101
|
+
# For #has_and_belongs_to_many, <tt>delete</tt> and <tt>destroy</tt> are the same: they
|
953
1102
|
# cause the records in the join table to be removed.
|
954
1103
|
#
|
955
|
-
# For
|
956
|
-
# record(s) being removed so that callbacks are run. However <tt>delete</tt> will either
|
1104
|
+
# For #has_many, <tt>destroy</tt> and <tt>destroy_all</tt> will always call the <tt>destroy</tt> method of the
|
1105
|
+
# record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either
|
957
1106
|
# do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
|
958
1107
|
# if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
|
959
|
-
# The default strategy is
|
960
|
-
#
|
1108
|
+
# The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for
|
1109
|
+
# #has_many <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete
|
961
1110
|
# the join records, without running their callbacks).
|
962
1111
|
#
|
963
1112
|
# There is also a <tt>clear</tt> method which is the same as <tt>delete_all</tt>, except that
|
@@ -965,16 +1114,16 @@ module ActiveRecord
|
|
965
1114
|
#
|
966
1115
|
# === What gets deleted?
|
967
1116
|
#
|
968
|
-
# There is a potential pitfall here:
|
1117
|
+
# There is a potential pitfall here: #has_and_belongs_to_many and #has_many <tt>:through</tt>
|
969
1118
|
# associations have records in join tables, as well as the associated records. So when we
|
970
1119
|
# call one of these deletion methods, what exactly should be deleted?
|
971
1120
|
#
|
972
1121
|
# The answer is that it is assumed that deletion on an association is about removing the
|
973
1122
|
# <i>link</i> between the owner and the associated object(s), rather than necessarily the
|
974
|
-
# associated objects themselves. So with
|
1123
|
+
# associated objects themselves. So with #has_and_belongs_to_many and #has_many
|
975
1124
|
# <tt>:through</tt>, the join records will be deleted, but the associated records won't.
|
976
1125
|
#
|
977
|
-
# This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.
|
1126
|
+
# This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.find_by(name: 'food'))</tt>
|
978
1127
|
# you would want the 'food' tag to be unlinked from the post, rather than for the tag itself
|
979
1128
|
# to be removed from the database.
|
980
1129
|
#
|
@@ -982,20 +1131,20 @@ module ActiveRecord
|
|
982
1131
|
# a person has many projects, and each project has many tasks. If we deleted one of a person's
|
983
1132
|
# tasks, we would probably not want the project to be deleted. In this scenario, the delete method
|
984
1133
|
# won't actually work: it can only be used if the association on the join model is a
|
985
|
-
#
|
1134
|
+
# #belongs_to. In other situations you are expected to perform operations directly on
|
986
1135
|
# either the associated records or the <tt>:through</tt> association.
|
987
1136
|
#
|
988
|
-
# With a regular
|
1137
|
+
# With a regular #has_many there is no distinction between the "associated records"
|
989
1138
|
# and the "link", so there is only one choice for what gets deleted.
|
990
1139
|
#
|
991
|
-
# With
|
1140
|
+
# With #has_and_belongs_to_many and #has_many <tt>:through</tt>, if you want to delete the
|
992
1141
|
# associated records themselves, you can always do something along the lines of
|
993
1142
|
# <tt>person.tasks.each(&:destroy)</tt>.
|
994
1143
|
#
|
995
|
-
# == Type safety with
|
1144
|
+
# == Type safety with ActiveRecord::AssociationTypeMismatch
|
996
1145
|
#
|
997
1146
|
# If you attempt to assign an object to an association that doesn't match the inferred
|
998
|
-
# or specified <tt>:class_name</tt>, you'll get an
|
1147
|
+
# or specified <tt>:class_name</tt>, you'll get an ActiveRecord::AssociationTypeMismatch.
|
999
1148
|
#
|
1000
1149
|
# == Options
|
1001
1150
|
#
|
@@ -1005,25 +1154,36 @@ module ActiveRecord
|
|
1005
1154
|
# Specifies a one-to-many association. The following methods for retrieval and query of
|
1006
1155
|
# collections of associated objects will be added:
|
1007
1156
|
#
|
1157
|
+
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
1158
|
+
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
|
1159
|
+
#
|
1008
1160
|
# [collection(force_reload = false)]
|
1009
1161
|
# Returns an array of all the associated objects.
|
1010
1162
|
# An empty array is returned if none are found.
|
1011
1163
|
# [collection<<(object, ...)]
|
1012
1164
|
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
|
1013
|
-
# Note that this operation instantly fires update
|
1014
|
-
# parent object.
|
1165
|
+
# Note that this operation instantly fires update SQL without waiting for the save or update call on the
|
1166
|
+
# parent object, unless the parent object is a new record.
|
1167
|
+
# This will also run validations and callbacks of associated object(s).
|
1015
1168
|
# [collection.delete(object, ...)]
|
1016
1169
|
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
|
1017
|
-
# Objects will be in addition destroyed if they're associated with <tt
|
1018
|
-
# and deleted if they're associated with <tt
|
1170
|
+
# Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>,
|
1171
|
+
# and deleted if they're associated with <tt>dependent: :delete_all</tt>.
|
1019
1172
|
#
|
1020
1173
|
# If the <tt>:through</tt> option is used, then the join records are deleted (rather than
|
1021
|
-
# nullified) by default, but you can specify <tt
|
1022
|
-
# <tt
|
1174
|
+
# nullified) by default, but you can specify <tt>dependent: :destroy</tt> or
|
1175
|
+
# <tt>dependent: :nullify</tt> to override this.
|
1176
|
+
# [collection.destroy(object, ...)]
|
1177
|
+
# Removes one or more objects from the collection by running <tt>destroy</tt> on
|
1178
|
+
# each record, regardless of any dependent option, ensuring callbacks are run.
|
1179
|
+
#
|
1180
|
+
# If the <tt>:through</tt> option is used, then the join records are destroyed
|
1181
|
+
# instead, not the objects themselves.
|
1023
1182
|
# [collection=objects]
|
1024
1183
|
# Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
|
1025
1184
|
# option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
|
1026
|
-
# direct.
|
1185
|
+
# direct by default. You can specify <tt>dependent: :destroy</tt> or
|
1186
|
+
# <tt>dependent: :nullify</tt> to override this.
|
1027
1187
|
# [collection_singular_ids]
|
1028
1188
|
# Returns an array of the associated objects' ids
|
1029
1189
|
# [collection_singular_ids=ids]
|
@@ -1031,8 +1191,8 @@ module ActiveRecord
|
|
1031
1191
|
# method loads the models and calls <tt>collection=</tt>. See above.
|
1032
1192
|
# [collection.clear]
|
1033
1193
|
# Removes every object from the collection. This destroys the associated objects if they
|
1034
|
-
# are associated with <tt
|
1035
|
-
# database if <tt
|
1194
|
+
# are associated with <tt>dependent: :destroy</tt>, deletes them directly from the
|
1195
|
+
# database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
|
1036
1196
|
# If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
|
1037
1197
|
# Join models are directly deleted.
|
1038
1198
|
# [collection.empty?]
|
@@ -1040,10 +1200,10 @@ module ActiveRecord
|
|
1040
1200
|
# [collection.size]
|
1041
1201
|
# Returns the number of associated objects.
|
1042
1202
|
# [collection.find(...)]
|
1043
|
-
# Finds an associated object according to the same rules as ActiveRecord::
|
1203
|
+
# Finds an associated object according to the same rules as ActiveRecord::FinderMethods#find.
|
1044
1204
|
# [collection.exists?(...)]
|
1045
1205
|
# Checks whether an associated object with the given conditions exists.
|
1046
|
-
# Uses the same rules as ActiveRecord::
|
1206
|
+
# Uses the same rules as ActiveRecord::FinderMethods#exists?.
|
1047
1207
|
# [collection.build(attributes = {}, ...)]
|
1048
1208
|
# Returns one or more new objects of the collection type that have been instantiated
|
1049
1209
|
# with +attributes+ and linked to this object through a foreign key, but have not yet
|
@@ -1053,97 +1213,101 @@ module ActiveRecord
|
|
1053
1213
|
# with +attributes+, linked to this object through a foreign key, and that has already
|
1054
1214
|
# been saved (if it passed the validation). *Note*: This only works if the base model
|
1055
1215
|
# already exists in the DB, not if it is a new (unsaved) record!
|
1056
|
-
#
|
1057
|
-
#
|
1058
|
-
#
|
1216
|
+
# [collection.create!(attributes = {})]
|
1217
|
+
# Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid
|
1218
|
+
# if the record is invalid.
|
1059
1219
|
#
|
1060
1220
|
# === Example
|
1061
1221
|
#
|
1062
|
-
#
|
1063
|
-
# * <tt>Firm#clients</tt> (similar to <tt>
|
1222
|
+
# A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
|
1223
|
+
# * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
|
1064
1224
|
# * <tt>Firm#clients<<</tt>
|
1065
1225
|
# * <tt>Firm#clients.delete</tt>
|
1226
|
+
# * <tt>Firm#clients.destroy</tt>
|
1066
1227
|
# * <tt>Firm#clients=</tt>
|
1067
1228
|
# * <tt>Firm#client_ids</tt>
|
1068
1229
|
# * <tt>Firm#client_ids=</tt>
|
1069
1230
|
# * <tt>Firm#clients.clear</tt>
|
1070
1231
|
# * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
|
1071
1232
|
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
|
1072
|
-
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.
|
1073
|
-
# * <tt>Firm#clients.exists?(:
|
1233
|
+
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
|
1234
|
+
# * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
|
1074
1235
|
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
|
1075
1236
|
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
|
1076
|
-
#
|
1237
|
+
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
|
1238
|
+
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1239
|
+
#
|
1240
|
+
# === Scopes
|
1241
|
+
#
|
1242
|
+
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
1243
|
+
# lambda) to retrieve a specific set of records or customize the generated
|
1244
|
+
# query when you access the associated collection.
|
1245
|
+
#
|
1246
|
+
# Scope examples:
|
1247
|
+
# has_many :comments, -> { where(author_id: 1) }
|
1248
|
+
# has_many :employees, -> { joins(:address) }
|
1249
|
+
# has_many :posts, ->(post) { where("max_post_length > ?", post.length) }
|
1250
|
+
#
|
1251
|
+
# === Extensions
|
1252
|
+
#
|
1253
|
+
# The +extension+ argument allows you to pass a block into a has_many
|
1254
|
+
# association. This is useful for adding new finders, creators and other
|
1255
|
+
# factory-type methods to be used as part of the association.
|
1256
|
+
#
|
1257
|
+
# Extension examples:
|
1258
|
+
# has_many :employees do
|
1259
|
+
# def find_or_create_by_name(name)
|
1260
|
+
# first_name, last_name = name.split(" ", 2)
|
1261
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
1262
|
+
# end
|
1263
|
+
# end
|
1077
1264
|
#
|
1078
1265
|
# === Options
|
1079
1266
|
# [:class_name]
|
1080
1267
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
1081
1268
|
# from the association name. So <tt>has_many :products</tt> will by default be linked
|
1082
|
-
# to the Product class, but if the real class name is SpecialProduct
|
1269
|
+
# to the +Product+ class, but if the real class name is +SpecialProduct+, you'll have to
|
1083
1270
|
# specify it with this option.
|
1084
|
-
# [:conditions]
|
1085
|
-
# Specify the conditions that the associated objects must meet in order to be included as a +WHERE+
|
1086
|
-
# SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. Record creations from
|
1087
|
-
# the association are scoped if a hash is used.
|
1088
|
-
# <tt>has_many :posts, :conditions => {:published => true}</tt> will create published
|
1089
|
-
# posts with <tt>@blog.posts.create</tt> or <tt>@blog.posts.build</tt>.
|
1090
|
-
# [:order]
|
1091
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1092
|
-
# such as <tt>last_name, first_name DESC</tt>.
|
1093
1271
|
# [:foreign_key]
|
1094
1272
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1095
|
-
# of this class in lower-case and "_id" suffixed. So a Person class that makes a
|
1273
|
+
# of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_many
|
1096
1274
|
# association will use "person_id" as the default <tt>:foreign_key</tt>.
|
1275
|
+
# [:foreign_type]
|
1276
|
+
# Specify the column used to store the associated object's type, if this is a polymorphic
|
1277
|
+
# association. By default this is guessed to be the name of the polymorphic association
|
1278
|
+
# specified on "as" option with a "_type" suffix. So a class that defines a
|
1279
|
+
# <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the
|
1280
|
+
# default <tt>:foreign_type</tt>.
|
1097
1281
|
# [:primary_key]
|
1098
|
-
# Specify the
|
1282
|
+
# Specify the name of the column to use as the primary key for the association. By default this is +id+.
|
1099
1283
|
# [:dependent]
|
1100
|
-
#
|
1101
|
-
#
|
1102
|
-
#
|
1103
|
-
#
|
1104
|
-
# <tt>:
|
1105
|
-
#
|
1284
|
+
# Controls what happens to the associated objects when
|
1285
|
+
# their owner is destroyed. Note that these are implemented as
|
1286
|
+
# callbacks, and Rails executes callbacks in order. Therefore, other
|
1287
|
+
# similar callbacks may affect the <tt>:dependent</tt> behavior, and the
|
1288
|
+
# <tt>:dependent</tt> behavior may affect other callbacks.
|
1289
|
+
#
|
1290
|
+
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
|
1291
|
+
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
|
1292
|
+
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
|
1293
|
+
# * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records.
|
1294
|
+
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
|
1106
1295
|
#
|
1107
1296
|
# If using with the <tt>:through</tt> option, the association on the join model must be
|
1108
|
-
# a
|
1297
|
+
# a #belongs_to, and the records which get deleted are the join records, rather than
|
1109
1298
|
# the associated records.
|
1110
|
-
#
|
1111
|
-
#
|
1112
|
-
#
|
1113
|
-
# associations that depend on multiple tables. May be supplied as a string or a proc where interpolation is
|
1114
|
-
# required. Note: When this option is used, +find_in_collection+
|
1115
|
-
# is _not_ added.
|
1116
|
-
# [:counter_sql]
|
1117
|
-
# Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
|
1118
|
-
# specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
|
1119
|
-
# replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
|
1120
|
-
# [:extend]
|
1121
|
-
# Specify a named module for extending the proxy. See "Association extensions".
|
1122
|
-
# [:include]
|
1123
|
-
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
1124
|
-
# [:group]
|
1125
|
-
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
1126
|
-
# [:having]
|
1127
|
-
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt>
|
1128
|
-
# returns. Uses the <tt>HAVING</tt> SQL-clause.
|
1129
|
-
# [:limit]
|
1130
|
-
# An integer determining the limit on the number of rows that should be returned.
|
1131
|
-
# [:offset]
|
1132
|
-
# An integer determining the offset from where the rows should be fetched. So at 5,
|
1133
|
-
# it would skip the first 4 rows.
|
1134
|
-
# [:select]
|
1135
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if
|
1136
|
-
# you, for example, want to do a join but not include the joined columns. Do not forget
|
1137
|
-
# to include the primary and foreign keys, otherwise it will raise an error.
|
1299
|
+
# [:counter_cache]
|
1300
|
+
# This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
|
1301
|
+
# when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association.
|
1138
1302
|
# [:as]
|
1139
|
-
# Specifies a polymorphic interface (See
|
1303
|
+
# Specifies a polymorphic interface (See #belongs_to).
|
1140
1304
|
# [:through]
|
1141
1305
|
# Specifies an association through which to perform the query. This can be any other type
|
1142
1306
|
# of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>,
|
1143
1307
|
# <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
|
1144
1308
|
# source reflection.
|
1145
1309
|
#
|
1146
|
-
# If the association on the join model is a
|
1310
|
+
# If the association on the join model is a #belongs_to, the collection can be modified
|
1147
1311
|
# and the records on the <tt>:through</tt> model will be automatically created and removed
|
1148
1312
|
# as appropriate. Otherwise, the collection is read-only, so you should manipulate the
|
1149
1313
|
# <tt>:through</tt> association directly.
|
@@ -1154,62 +1318,65 @@ module ActiveRecord
|
|
1154
1318
|
# the appropriate join model records when they are saved. (See the 'Association Join Models'
|
1155
1319
|
# section above.)
|
1156
1320
|
# [:source]
|
1157
|
-
# Specifies the source association name used by <tt
|
1321
|
+
# Specifies the source association name used by #has_many <tt>:through</tt> queries.
|
1158
1322
|
# Only use it if the name cannot be inferred from the association.
|
1159
|
-
# <tt>has_many :subscribers, :
|
1323
|
+
# <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
|
1160
1324
|
# <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
|
1161
1325
|
# [:source_type]
|
1162
|
-
# Specifies type of the source association used by <tt
|
1163
|
-
# association is a polymorphic
|
1164
|
-
# [:uniq]
|
1165
|
-
# If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
|
1166
|
-
# [:readonly]
|
1167
|
-
# If true, all the associated objects are readonly through the association.
|
1326
|
+
# Specifies type of the source association used by #has_many <tt>:through</tt> queries where the source
|
1327
|
+
# association is a polymorphic #belongs_to.
|
1168
1328
|
# [:validate]
|
1169
|
-
#
|
1329
|
+
# When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
|
1330
|
+
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
1170
1331
|
# [:autosave]
|
1171
1332
|
# If true, always save the associated objects or destroy them if marked for destruction,
|
1172
1333
|
# when saving the parent object. If false, never save or destroy the associated objects.
|
1173
|
-
# By default, only save associated objects that are new records.
|
1334
|
+
# By default, only save associated objects that are new records. This option is implemented as a
|
1335
|
+
# +before_save+ callback. Because callbacks are run in the order they are defined, associated objects
|
1336
|
+
# may need to be explicitly saved in any user-defined +before_save+ callbacks.
|
1337
|
+
#
|
1338
|
+
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
1339
|
+
# <tt>:autosave</tt> to <tt>true</tt>.
|
1174
1340
|
# [:inverse_of]
|
1175
|
-
# Specifies the name of the
|
1176
|
-
# that is the inverse of this
|
1341
|
+
# Specifies the name of the #belongs_to association on the associated object
|
1342
|
+
# that is the inverse of this #has_many association. Does not work in combination
|
1177
1343
|
# with <tt>:through</tt> or <tt>:as</tt> options.
|
1178
1344
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1345
|
+
# [:extend]
|
1346
|
+
# Specifies a module or array of modules that will be extended into the association object returned.
|
1347
|
+
# Useful for defining methods on associations, especially when they should be shared between multiple
|
1348
|
+
# association objects.
|
1179
1349
|
#
|
1180
1350
|
# Option examples:
|
1181
|
-
# has_many :comments,
|
1182
|
-
# has_many :comments,
|
1183
|
-
# has_many :people,
|
1184
|
-
# has_many :tracks,
|
1185
|
-
# has_many :comments, :
|
1186
|
-
# has_many :tags, :
|
1187
|
-
# has_many :reports,
|
1188
|
-
# has_many :subscribers, :
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
# FROM people p, post_subscriptions ps
|
1193
|
-
# WHERE ps.post_id = #{id} AND ps.person_id = p.id
|
1194
|
-
# ORDER BY p.first_name
|
1195
|
-
# }
|
1196
|
-
# }
|
1197
|
-
def has_many(name, options = {}, &extension)
|
1198
|
-
Builder::HasMany.build(self, name, options, &extension)
|
1351
|
+
# has_many :comments, -> { order("posted_on") }
|
1352
|
+
# has_many :comments, -> { includes(:author) }
|
1353
|
+
# has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person"
|
1354
|
+
# has_many :tracks, -> { order("position") }, dependent: :destroy
|
1355
|
+
# has_many :comments, dependent: :nullify
|
1356
|
+
# has_many :tags, as: :taggable
|
1357
|
+
# has_many :reports, -> { readonly }
|
1358
|
+
# has_many :subscribers, through: :subscriptions, source: :user
|
1359
|
+
def has_many(name, scope = nil, options = {}, &extension)
|
1360
|
+
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
1361
|
+
Reflection.add_reflection self, name, reflection
|
1199
1362
|
end
|
1200
1363
|
|
1201
1364
|
# Specifies a one-to-one association with another class. This method should only be used
|
1202
1365
|
# if the other class contains the foreign key. If the current class contains the foreign key,
|
1203
|
-
# then you should use
|
1204
|
-
# on when to use has_one and when to use belongs_to.
|
1366
|
+
# then you should use #belongs_to instead. See also ActiveRecord::Associations::ClassMethods's overview
|
1367
|
+
# on when to use #has_one and when to use #belongs_to.
|
1205
1368
|
#
|
1206
1369
|
# The following methods for retrieval and query of a single associated object will be added:
|
1207
1370
|
#
|
1371
|
+
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
1372
|
+
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
|
1373
|
+
#
|
1208
1374
|
# [association(force_reload = false)]
|
1209
1375
|
# Returns the associated object. +nil+ is returned if none is found.
|
1210
1376
|
# [association=(associate)]
|
1211
1377
|
# Assigns the associate object, extracts the primary key, sets it as the foreign key,
|
1212
|
-
# and saves the associate object.
|
1378
|
+
# and saves the associate object. To avoid database inconsistencies, permanently deletes an existing
|
1379
|
+
# associated object when assigning a new one, even if the new one isn't saved to database.
|
1213
1380
|
# [build_association(attributes = {})]
|
1214
1381
|
# Returns a new object of the associated type that has been instantiated
|
1215
1382
|
# with +attributes+ and linked to this object through a foreign key, but has not
|
@@ -1219,107 +1386,123 @@ module ActiveRecord
|
|
1219
1386
|
# with +attributes+, linked to this object through a foreign key, and that
|
1220
1387
|
# has already been saved (if it passed the validation).
|
1221
1388
|
# [create_association!(attributes = {})]
|
1222
|
-
# Does the same as <tt>create_association</tt>, but raises
|
1389
|
+
# Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
|
1223
1390
|
# if the record is invalid.
|
1224
1391
|
#
|
1225
|
-
# (+association+ is replaced with the symbol passed as the first argument, so
|
1226
|
-
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.)
|
1227
|
-
#
|
1228
1392
|
# === Example
|
1229
1393
|
#
|
1230
1394
|
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
|
1231
|
-
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.
|
1395
|
+
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
|
1232
1396
|
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
|
1233
1397
|
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
|
1234
1398
|
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
|
1235
1399
|
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
|
1236
1400
|
#
|
1401
|
+
# === Scopes
|
1402
|
+
#
|
1403
|
+
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
1404
|
+
# lambda) to retrieve a specific record or customize the generated query
|
1405
|
+
# when you access the associated object.
|
1406
|
+
#
|
1407
|
+
# Scope examples:
|
1408
|
+
# has_one :author, -> { where(comment_id: 1) }
|
1409
|
+
# has_one :employer, -> { joins(:company) }
|
1410
|
+
# has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) }
|
1411
|
+
#
|
1237
1412
|
# === Options
|
1238
1413
|
#
|
1239
|
-
# The declaration can also include an options hash to specialize the behavior of the association.
|
1414
|
+
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1240
1415
|
#
|
1241
1416
|
# Options are:
|
1242
1417
|
# [:class_name]
|
1243
1418
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
1244
1419
|
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
|
1245
1420
|
# if the real class name is Person, you'll have to specify it with this option.
|
1246
|
-
# [:conditions]
|
1247
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1248
|
-
# SQL fragment, such as <tt>rank = 5</tt>. Record creation from the association is scoped if a hash
|
1249
|
-
# is used. <tt>has_one :account, :conditions => {:enabled => true}</tt> will create
|
1250
|
-
# an enabled account with <tt>@company.create_account</tt> or <tt>@company.build_account</tt>.
|
1251
|
-
# [:order]
|
1252
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1253
|
-
# such as <tt>last_name, first_name DESC</tt>.
|
1254
1421
|
# [:dependent]
|
1255
|
-
#
|
1256
|
-
#
|
1257
|
-
#
|
1258
|
-
#
|
1259
|
-
# <tt
|
1422
|
+
# Controls what happens to the associated object when
|
1423
|
+
# its owner is destroyed:
|
1424
|
+
#
|
1425
|
+
# * <tt>:destroy</tt> causes the associated object to also be destroyed
|
1426
|
+
# * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
|
1427
|
+
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
|
1428
|
+
# * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record
|
1429
|
+
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
|
1430
|
+
#
|
1431
|
+
# Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option.
|
1260
1432
|
# [:foreign_key]
|
1261
1433
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1262
|
-
# of this class in lower-case and "_id" suffixed. So a Person class that makes a
|
1434
|
+
# of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_one association
|
1263
1435
|
# will use "person_id" as the default <tt>:foreign_key</tt>.
|
1436
|
+
# [:foreign_type]
|
1437
|
+
# Specify the column used to store the associated object's type, if this is a polymorphic
|
1438
|
+
# association. By default this is guessed to be the name of the polymorphic association
|
1439
|
+
# specified on "as" option with a "_type" suffix. So a class that defines a
|
1440
|
+
# <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the
|
1441
|
+
# default <tt>:foreign_type</tt>.
|
1264
1442
|
# [:primary_key]
|
1265
1443
|
# Specify the method that returns the primary key used for the association. By default this is +id+.
|
1266
|
-
# [:include]
|
1267
|
-
# Specify second-order associations that should be eager loaded when this object is loaded.
|
1268
1444
|
# [:as]
|
1269
|
-
# Specifies a polymorphic interface (See
|
1270
|
-
# [:select]
|
1271
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example,
|
1272
|
-
# you want to do a join but not include the joined columns. Do not forget to include the
|
1273
|
-
# primary and foreign keys, otherwise it will raise an error.
|
1445
|
+
# Specifies a polymorphic interface (See #belongs_to).
|
1274
1446
|
# [:through]
|
1275
1447
|
# Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
|
1276
1448
|
# <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
|
1277
|
-
# source reflection. You can only use a <tt>:through</tt> query through a
|
1278
|
-
# or
|
1449
|
+
# source reflection. You can only use a <tt>:through</tt> query through a #has_one
|
1450
|
+
# or #belongs_to association on the join model.
|
1279
1451
|
# [:source]
|
1280
|
-
# Specifies the source association name used by <tt
|
1452
|
+
# Specifies the source association name used by #has_one <tt>:through</tt> queries.
|
1281
1453
|
# Only use it if the name cannot be inferred from the association.
|
1282
|
-
# <tt>has_one :favorite, :
|
1454
|
+
# <tt>has_one :favorite, through: :favorites</tt> will look for a
|
1283
1455
|
# <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
|
1284
1456
|
# [:source_type]
|
1285
|
-
# Specifies type of the source association used by <tt
|
1286
|
-
# association is a polymorphic
|
1287
|
-
# [:readonly]
|
1288
|
-
# If true, the associated object is readonly through the association.
|
1457
|
+
# Specifies type of the source association used by #has_one <tt>:through</tt> queries where the source
|
1458
|
+
# association is a polymorphic #belongs_to.
|
1289
1459
|
# [:validate]
|
1290
|
-
#
|
1460
|
+
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
1461
|
+
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
1291
1462
|
# [:autosave]
|
1292
1463
|
# If true, always save the associated object or destroy it if marked for destruction,
|
1293
1464
|
# when saving the parent object. If false, never save or destroy the associated object.
|
1294
1465
|
# By default, only save the associated object if it's a new record.
|
1466
|
+
#
|
1467
|
+
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
1468
|
+
# <tt>:autosave</tt> to <tt>true</tt>.
|
1295
1469
|
# [:inverse_of]
|
1296
|
-
# Specifies the name of the
|
1297
|
-
# that is the inverse of this
|
1470
|
+
# Specifies the name of the #belongs_to association on the associated object
|
1471
|
+
# that is the inverse of this #has_one association. Does not work in combination
|
1298
1472
|
# with <tt>:through</tt> or <tt>:as</tt> options.
|
1299
1473
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1474
|
+
# [:required]
|
1475
|
+
# When set to +true+, the association will also have its presence validated.
|
1476
|
+
# This will validate the association itself, not the id. You can use
|
1477
|
+
# +:inverse_of+ to avoid an extra query during validation.
|
1300
1478
|
#
|
1301
1479
|
# Option examples:
|
1302
|
-
# has_one :credit_card, :
|
1303
|
-
# has_one :credit_card, :
|
1480
|
+
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
1481
|
+
# has_one :credit_card, dependent: :nullify # updates the associated records foreign
|
1304
1482
|
# # key value to NULL rather than destroying it
|
1305
|
-
# has_one :last_comment,
|
1306
|
-
# has_one :project_manager, :
|
1307
|
-
# has_one :attachment, :
|
1308
|
-
# has_one :boss,
|
1309
|
-
# has_one :club, :
|
1310
|
-
# has_one :primary_address, :
|
1311
|
-
|
1312
|
-
|
1483
|
+
# has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
|
1484
|
+
# has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
|
1485
|
+
# has_one :attachment, as: :attachable
|
1486
|
+
# has_one :boss, -> { readonly }
|
1487
|
+
# has_one :club, through: :membership
|
1488
|
+
# has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
|
1489
|
+
# has_one :credit_card, required: true
|
1490
|
+
def has_one(name, scope = nil, options = {})
|
1491
|
+
reflection = Builder::HasOne.build(self, name, scope, options)
|
1492
|
+
Reflection.add_reflection self, name, reflection
|
1313
1493
|
end
|
1314
1494
|
|
1315
1495
|
# Specifies a one-to-one association with another class. This method should only be used
|
1316
1496
|
# if this class contains the foreign key. If the other class contains the foreign key,
|
1317
|
-
# then you should use
|
1318
|
-
# on when to use
|
1497
|
+
# then you should use #has_one instead. See also ActiveRecord::Associations::ClassMethods's overview
|
1498
|
+
# on when to use #has_one and when to use #belongs_to.
|
1319
1499
|
#
|
1320
1500
|
# Methods will be added for retrieval and query for a single associated object, for which
|
1321
1501
|
# this object holds an id:
|
1322
1502
|
#
|
1503
|
+
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
1504
|
+
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
|
1505
|
+
#
|
1323
1506
|
# [association(force_reload = false)]
|
1324
1507
|
# Returns the associated object. +nil+ is returned if none is found.
|
1325
1508
|
# [association=(associate)]
|
@@ -1332,12 +1515,9 @@ module ActiveRecord
|
|
1332
1515
|
# with +attributes+, linked to this object through a foreign key, and that
|
1333
1516
|
# has already been saved (if it passed the validation).
|
1334
1517
|
# [create_association!(attributes = {})]
|
1335
|
-
# Does the same as <tt>create_association</tt>, but raises
|
1518
|
+
# Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
|
1336
1519
|
# if the record is invalid.
|
1337
1520
|
#
|
1338
|
-
# (+association+ is replaced with the symbol passed as the first argument, so
|
1339
|
-
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.)
|
1340
|
-
#
|
1341
1521
|
# === Example
|
1342
1522
|
#
|
1343
1523
|
# A Post class declares <tt>belongs_to :author</tt>, which will add:
|
@@ -1346,7 +1526,18 @@ module ActiveRecord
|
|
1346
1526
|
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
|
1347
1527
|
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
|
1348
1528
|
# * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
|
1349
|
-
# The declaration can also include an options hash to specialize the behavior of the association.
|
1529
|
+
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1530
|
+
#
|
1531
|
+
# === Scopes
|
1532
|
+
#
|
1533
|
+
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
1534
|
+
# lambda) to retrieve a specific record or customize the generated query
|
1535
|
+
# when you access the associated object.
|
1536
|
+
#
|
1537
|
+
# Scope examples:
|
1538
|
+
# belongs_to :firm, -> { where(id: 2) }
|
1539
|
+
# belongs_to :user, -> { joins(:friends) }
|
1540
|
+
# belongs_to :level, ->(level) { where("game_level > ?", level.current) }
|
1350
1541
|
#
|
1351
1542
|
# === Options
|
1352
1543
|
#
|
@@ -1354,23 +1545,16 @@ module ActiveRecord
|
|
1354
1545
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
1355
1546
|
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
|
1356
1547
|
# if the real class name is Person, you'll have to specify it with this option.
|
1357
|
-
# [:conditions]
|
1358
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1359
|
-
# SQL fragment, such as <tt>authorized = 1</tt>.
|
1360
|
-
# [:select]
|
1361
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed
|
1362
|
-
# if, for example, you want to do a join but not include the joined columns. Do not
|
1363
|
-
# forget to include the primary and foreign keys, otherwise it will raise an error.
|
1364
1548
|
# [:foreign_key]
|
1365
1549
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1366
1550
|
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
|
1367
1551
|
# association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
|
1368
|
-
# <tt>belongs_to :favorite_person, :
|
1552
|
+
# <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key
|
1369
1553
|
# of "favorite_person_id".
|
1370
1554
|
# [:foreign_type]
|
1371
1555
|
# Specify the column used to store the associated object's type, if this is a polymorphic
|
1372
1556
|
# association. By default this is guessed to be the name of the association with a "_type"
|
1373
|
-
# suffix. So a class that defines a <tt>belongs_to :taggable, :
|
1557
|
+
# suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt>
|
1374
1558
|
# association will use "taggable_type" as the default <tt>:foreign_type</tt>.
|
1375
1559
|
# [:primary_key]
|
1376
1560
|
# Specify the method that returns the primary key of associated object used for the association.
|
@@ -1378,63 +1562,77 @@ module ActiveRecord
|
|
1378
1562
|
# [:dependent]
|
1379
1563
|
# If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
|
1380
1564
|
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
|
1381
|
-
# This option should not be specified when
|
1382
|
-
# a
|
1565
|
+
# This option should not be specified when #belongs_to is used in conjunction with
|
1566
|
+
# a #has_many relationship on another class because of the potential to leave
|
1383
1567
|
# orphaned records behind.
|
1384
1568
|
# [:counter_cache]
|
1385
|
-
# Caches the number of belonging objects on the associate class through the use of
|
1386
|
-
# and
|
1569
|
+
# Caches the number of belonging objects on the associate class through the use of CounterCache::ClassMethods#increment_counter
|
1570
|
+
# and CounterCache::ClassMethods#decrement_counter. The counter cache is incremented when an object of this
|
1387
1571
|
# class is created and decremented when it's destroyed. This requires that a column
|
1388
1572
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
1389
|
-
# is used on the associate class (such as a Post class)
|
1573
|
+
# is used on the associate class (such as a Post class) - that is the migration for
|
1574
|
+
# <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
|
1575
|
+
# return the count cached, see note below). You can also specify a custom counter
|
1390
1576
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
1391
|
-
# option (e.g., <tt
|
1577
|
+
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
1392
1578
|
# Note: Specifying a counter cache will add it to that model's list of readonly attributes
|
1393
1579
|
# using +attr_readonly+.
|
1394
|
-
# [:include]
|
1395
|
-
# Specify second-order associations that should be eager loaded when this object is loaded.
|
1396
1580
|
# [:polymorphic]
|
1397
1581
|
# Specify this association is a polymorphic association by passing +true+.
|
1398
1582
|
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
1399
1583
|
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
1400
|
-
# [:readonly]
|
1401
|
-
# If true, the associated object is readonly through the association.
|
1402
1584
|
# [:validate]
|
1403
|
-
#
|
1585
|
+
# When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
|
1586
|
+
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
1404
1587
|
# [:autosave]
|
1405
1588
|
# If true, always save the associated object or destroy it if marked for destruction, when
|
1406
1589
|
# saving the parent object.
|
1407
1590
|
# If false, never save or destroy the associated object.
|
1408
1591
|
# By default, only save the associated object if it's a new record.
|
1592
|
+
#
|
1593
|
+
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for
|
1594
|
+
# sets <tt>:autosave</tt> to <tt>true</tt>.
|
1409
1595
|
# [:touch]
|
1410
|
-
# If true, the associated object will be touched (the updated_at/on attributes set to
|
1596
|
+
# If true, the associated object will be touched (the updated_at/on attributes set to current time)
|
1411
1597
|
# when this record is either saved or destroyed. If you specify a symbol, that attribute
|
1412
1598
|
# will be updated with the current time in addition to the updated_at/on attribute.
|
1599
|
+
# Please note that with touching no validation is performed and only the +after_touch+,
|
1600
|
+
# +after_commit+ and +after_rollback+ callbacks are executed.
|
1413
1601
|
# [:inverse_of]
|
1414
|
-
# Specifies the name of the
|
1415
|
-
# object that is the inverse of this
|
1602
|
+
# Specifies the name of the #has_one or #has_many association on the associated
|
1603
|
+
# object that is the inverse of this #belongs_to association. Does not work in
|
1416
1604
|
# combination with the <tt>:polymorphic</tt> options.
|
1417
1605
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1606
|
+
# [:optional]
|
1607
|
+
# When set to +true+, the association will not have its presence validated.
|
1608
|
+
# [:required]
|
1609
|
+
# When set to +true+, the association will also have its presence validated.
|
1610
|
+
# This will validate the association itself, not the id. You can use
|
1611
|
+
# +:inverse_of+ to avoid an extra query during validation.
|
1612
|
+
# NOTE: <tt>required</tt> is set to <tt>true</tt> by default and is deprecated. If
|
1613
|
+
# you don't want to have association presence validated, use <tt>optional: true</tt>.
|
1418
1614
|
#
|
1419
1615
|
# Option examples:
|
1420
|
-
# belongs_to :firm, :
|
1421
|
-
# belongs_to :person, :
|
1422
|
-
# belongs_to :author, :
|
1423
|
-
# belongs_to :valid_coupon,
|
1424
|
-
#
|
1425
|
-
# belongs_to :attachable, :
|
1426
|
-
# belongs_to :project,
|
1427
|
-
# belongs_to :post, :
|
1428
|
-
# belongs_to :
|
1429
|
-
# belongs_to :company, :
|
1430
|
-
|
1431
|
-
|
1616
|
+
# belongs_to :firm, foreign_key: "client_of"
|
1617
|
+
# belongs_to :person, primary_key: "name", foreign_key: "person_name"
|
1618
|
+
# belongs_to :author, class_name: "Person", foreign_key: "author_id"
|
1619
|
+
# belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count },
|
1620
|
+
# class_name: "Coupon", foreign_key: "coupon_id"
|
1621
|
+
# belongs_to :attachable, polymorphic: true
|
1622
|
+
# belongs_to :project, -> { readonly }
|
1623
|
+
# belongs_to :post, counter_cache: true
|
1624
|
+
# belongs_to :comment, touch: true
|
1625
|
+
# belongs_to :company, touch: :employees_last_updated_at
|
1626
|
+
# belongs_to :user, optional: true
|
1627
|
+
def belongs_to(name, scope = nil, options = {})
|
1628
|
+
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
1629
|
+
Reflection.add_reflection self, name, reflection
|
1432
1630
|
end
|
1433
1631
|
|
1434
1632
|
# Specifies a many-to-many relationship with another class. This associates two classes via an
|
1435
1633
|
# intermediate join table. Unless the join table is explicitly specified as an option, it is
|
1436
1634
|
# guessed using the lexical order of the class names. So a join between Developer and Project
|
1437
|
-
# will give the default join table name of "developers_projects" because "D"
|
1635
|
+
# will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically.
|
1438
1636
|
# Note that this precedence is calculated using the <tt><</tt> operator for String. This
|
1439
1637
|
# means that if the strings are of different lengths, and the strings are equal when compared
|
1440
1638
|
# up to the shortest length, then the longer string is considered of higher
|
@@ -1442,16 +1640,15 @@ module ActiveRecord
|
|
1442
1640
|
# to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
|
1443
1641
|
# but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
|
1444
1642
|
# custom <tt>:join_table</tt> option if you need to.
|
1643
|
+
# If your tables share a common prefix, it will only appear once at the beginning. For example,
|
1644
|
+
# the tables "catalog_categories" and "catalog_products" generate a join table name of "catalog_categories_products".
|
1445
1645
|
#
|
1446
1646
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
1447
1647
|
# join table with a migration such as this:
|
1448
1648
|
#
|
1449
|
-
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
|
1649
|
+
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[5.0]
|
1450
1650
|
# def change
|
1451
|
-
#
|
1452
|
-
# t.integer :developer_id
|
1453
|
-
# t.integer :project_id
|
1454
|
-
# end
|
1651
|
+
# create_join_table :developers, :projects
|
1455
1652
|
# end
|
1456
1653
|
# end
|
1457
1654
|
#
|
@@ -1461,17 +1658,23 @@ module ActiveRecord
|
|
1461
1658
|
#
|
1462
1659
|
# Adds the following methods for retrieval and query:
|
1463
1660
|
#
|
1661
|
+
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
1662
|
+
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
|
1663
|
+
#
|
1464
1664
|
# [collection(force_reload = false)]
|
1465
1665
|
# Returns an array of all the associated objects.
|
1466
1666
|
# An empty array is returned if none are found.
|
1467
1667
|
# [collection<<(object, ...)]
|
1468
1668
|
# Adds one or more objects to the collection by creating associations in the join table
|
1469
1669
|
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
|
1470
|
-
# Note that this operation instantly fires update
|
1471
|
-
# parent object.
|
1670
|
+
# Note that this operation instantly fires update SQL without waiting for the save or update call on the
|
1671
|
+
# parent object, unless the parent object is a new record.
|
1472
1672
|
# [collection.delete(object, ...)]
|
1473
1673
|
# Removes one or more objects from the collection by removing their associations from the join table.
|
1474
1674
|
# This does not destroy the objects.
|
1675
|
+
# [collection.destroy(object, ...)]
|
1676
|
+
# Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
|
1677
|
+
# This does not destroy the objects.
|
1475
1678
|
# [collection=objects]
|
1476
1679
|
# Replaces the collection's content by deleting and adding objects as appropriate.
|
1477
1680
|
# [collection_singular_ids]
|
@@ -1487,10 +1690,10 @@ module ActiveRecord
|
|
1487
1690
|
# [collection.find(id)]
|
1488
1691
|
# Finds an associated object responding to the +id+ and that
|
1489
1692
|
# meets the condition that it has to be associated with this object.
|
1490
|
-
# Uses the same rules as ActiveRecord::
|
1693
|
+
# Uses the same rules as ActiveRecord::FinderMethods#find.
|
1491
1694
|
# [collection.exists?(...)]
|
1492
1695
|
# Checks whether an associated object with the given conditions exists.
|
1493
|
-
# Uses the same rules as ActiveRecord::
|
1696
|
+
# Uses the same rules as ActiveRecord::FinderMethods#exists?.
|
1494
1697
|
# [collection.build(attributes = {})]
|
1495
1698
|
# Returns a new object of the collection type that has been instantiated
|
1496
1699
|
# with +attributes+ and linked to this object through the join table, but has not yet been saved.
|
@@ -1499,15 +1702,13 @@ module ActiveRecord
|
|
1499
1702
|
# with +attributes+, linked to this object through the join table, and that has already been
|
1500
1703
|
# saved (if it passed the validation).
|
1501
1704
|
#
|
1502
|
-
# (+collection+ is replaced with the symbol passed as the first argument, so
|
1503
|
-
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.)
|
1504
|
-
#
|
1505
1705
|
# === Example
|
1506
1706
|
#
|
1507
1707
|
# A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
|
1508
1708
|
# * <tt>Developer#projects</tt>
|
1509
1709
|
# * <tt>Developer#projects<<</tt>
|
1510
1710
|
# * <tt>Developer#projects.delete</tt>
|
1711
|
+
# * <tt>Developer#projects.destroy</tt>
|
1511
1712
|
# * <tt>Developer#projects=</tt>
|
1512
1713
|
# * <tt>Developer#project_ids</tt>
|
1513
1714
|
# * <tt>Developer#project_ids=</tt>
|
@@ -1518,7 +1719,34 @@ module ActiveRecord
|
|
1518
1719
|
# * <tt>Developer#projects.exists?(...)</tt>
|
1519
1720
|
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
|
1520
1721
|
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
|
1521
|
-
# The declaration may include an options hash to specialize the behavior of the association.
|
1722
|
+
# The declaration may include an +options+ hash to specialize the behavior of the association.
|
1723
|
+
#
|
1724
|
+
# === Scopes
|
1725
|
+
#
|
1726
|
+
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
1727
|
+
# lambda) to retrieve a specific set of records or customize the generated
|
1728
|
+
# query when you access the associated collection.
|
1729
|
+
#
|
1730
|
+
# Scope examples:
|
1731
|
+
# has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
|
1732
|
+
# has_and_belongs_to_many :categories, ->(category) {
|
1733
|
+
# where("default_category = ?", category.name)
|
1734
|
+
# }
|
1735
|
+
#
|
1736
|
+
# === Extensions
|
1737
|
+
#
|
1738
|
+
# The +extension+ argument allows you to pass a block into a
|
1739
|
+
# has_and_belongs_to_many association. This is useful for adding new
|
1740
|
+
# finders, creators and other factory-type methods to be used as part of
|
1741
|
+
# the association.
|
1742
|
+
#
|
1743
|
+
# Extension examples:
|
1744
|
+
# has_and_belongs_to_many :contractors do
|
1745
|
+
# def find_or_create_by_name(name)
|
1746
|
+
# first_name, last_name = name.split(" ", 2)
|
1747
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
1748
|
+
# end
|
1749
|
+
# end
|
1522
1750
|
#
|
1523
1751
|
# === Options
|
1524
1752
|
#
|
@@ -1529,78 +1757,76 @@ module ActiveRecord
|
|
1529
1757
|
# [:join_table]
|
1530
1758
|
# Specify the name of the join table if the default based on lexical order isn't what you want.
|
1531
1759
|
# <b>WARNING:</b> If you're overwriting the table name of either class, the +table_name+ method
|
1532
|
-
# MUST be declared underneath any
|
1760
|
+
# MUST be declared underneath any #has_and_belongs_to_many declaration in order to work.
|
1533
1761
|
# [:foreign_key]
|
1534
1762
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1535
1763
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes
|
1536
|
-
# a
|
1764
|
+
# a #has_and_belongs_to_many association to Project will use "person_id" as the
|
1537
1765
|
# default <tt>:foreign_key</tt>.
|
1538
1766
|
# [:association_foreign_key]
|
1539
1767
|
# Specify the foreign key used for the association on the receiving side of the association.
|
1540
1768
|
# By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
|
1541
|
-
# So if a Person class makes a
|
1769
|
+
# So if a Person class makes a #has_and_belongs_to_many association to Project,
|
1542
1770
|
# the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
|
1543
|
-
# [:conditions]
|
1544
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1545
|
-
# SQL fragment, such as <tt>authorized = 1</tt>. Record creations from the association are
|
1546
|
-
# scoped if a hash is used.
|
1547
|
-
# <tt>has_many :posts, :conditions => {:published => true}</tt> will create published posts with <tt>@blog.posts.create</tt>
|
1548
|
-
# or <tt>@blog.posts.build</tt>.
|
1549
|
-
# [:order]
|
1550
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1551
|
-
# such as <tt>last_name, first_name DESC</tt>
|
1552
|
-
# [:uniq]
|
1553
|
-
# If true, duplicate associated objects will be ignored by accessors and query methods.
|
1554
|
-
# [:finder_sql]
|
1555
|
-
# Overwrite the default generated SQL statement used to fetch the association with a manual statement
|
1556
|
-
# [:counter_sql]
|
1557
|
-
# Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
|
1558
|
-
# specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
|
1559
|
-
# replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
|
1560
|
-
# [:delete_sql]
|
1561
|
-
# Overwrite the default generated SQL statement used to remove links between the associated
|
1562
|
-
# classes with a manual statement.
|
1563
|
-
# [:insert_sql]
|
1564
|
-
# Overwrite the default generated SQL statement used to add links between the associated classes
|
1565
|
-
# with a manual statement.
|
1566
|
-
# [:extend]
|
1567
|
-
# Anonymous module for extending the proxy, see "Association extensions".
|
1568
|
-
# [:include]
|
1569
|
-
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
1570
|
-
# [:group]
|
1571
|
-
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
1572
|
-
# [:having]
|
1573
|
-
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns.
|
1574
|
-
# Uses the <tt>HAVING</tt> SQL-clause.
|
1575
|
-
# [:limit]
|
1576
|
-
# An integer determining the limit on the number of rows that should be returned.
|
1577
|
-
# [:offset]
|
1578
|
-
# An integer determining the offset from where the rows should be fetched. So at 5,
|
1579
|
-
# it would skip the first 4 rows.
|
1580
|
-
# [:select]
|
1581
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example,
|
1582
|
-
# you want to do a join but not include the joined columns. Do not forget to include the primary
|
1583
|
-
# and foreign keys, otherwise it will raise an error.
|
1584
|
-
# [:readonly]
|
1585
|
-
# If true, all the associated objects are readonly through the association.
|
1586
1771
|
# [:validate]
|
1587
|
-
#
|
1772
|
+
# When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
|
1773
|
+
# If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
|
1588
1774
|
# [:autosave]
|
1589
1775
|
# If true, always save the associated objects or destroy them if marked for destruction, when
|
1590
1776
|
# saving the parent object.
|
1591
1777
|
# If false, never save or destroy the associated objects.
|
1592
1778
|
# By default, only save associated objects that are new records.
|
1593
1779
|
#
|
1780
|
+
# Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
|
1781
|
+
# <tt>:autosave</tt> to <tt>true</tt>.
|
1782
|
+
#
|
1594
1783
|
# Option examples:
|
1595
1784
|
# has_and_belongs_to_many :projects
|
1596
|
-
# has_and_belongs_to_many :projects,
|
1597
|
-
# has_and_belongs_to_many :nations, :
|
1598
|
-
# has_and_belongs_to_many :categories, :
|
1599
|
-
# has_and_belongs_to_many :categories,
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1785
|
+
# has_and_belongs_to_many :projects, -> { includes(:milestones, :manager) }
|
1786
|
+
# has_and_belongs_to_many :nations, class_name: "Country"
|
1787
|
+
# has_and_belongs_to_many :categories, join_table: "prods_cats"
|
1788
|
+
# has_and_belongs_to_many :categories, -> { readonly }
|
1789
|
+
def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
|
1790
|
+
if scope.is_a?(Hash)
|
1791
|
+
options = scope
|
1792
|
+
scope = nil
|
1793
|
+
end
|
1794
|
+
|
1795
|
+
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
1796
|
+
|
1797
|
+
builder = Builder::HasAndBelongsToMany.new name, self, options
|
1798
|
+
|
1799
|
+
join_model = builder.through_model
|
1800
|
+
|
1801
|
+
const_set join_model.name, join_model
|
1802
|
+
private_constant join_model.name
|
1803
|
+
|
1804
|
+
middle_reflection = builder.middle_reflection join_model
|
1805
|
+
|
1806
|
+
Builder::HasMany.define_callbacks self, middle_reflection
|
1807
|
+
Reflection.add_reflection self, middle_reflection.name, middle_reflection
|
1808
|
+
middle_reflection.parent_reflection = habtm_reflection
|
1809
|
+
|
1810
|
+
include Module.new {
|
1811
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
1812
|
+
def destroy_associations
|
1813
|
+
association(:#{middle_reflection.name}).delete_all(:delete_all)
|
1814
|
+
association(:#{name}).reset
|
1815
|
+
super
|
1816
|
+
end
|
1817
|
+
RUBY
|
1818
|
+
}
|
1819
|
+
|
1820
|
+
hm_options = {}
|
1821
|
+
hm_options[:through] = middle_reflection.name
|
1822
|
+
hm_options[:source] = join_model.right_reflection.name
|
1823
|
+
|
1824
|
+
[:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
|
1825
|
+
hm_options[k] = options[k] if options.key? k
|
1826
|
+
end
|
1827
|
+
|
1828
|
+
has_many name, scope, hm_options, &extension
|
1829
|
+
self._reflections[name.to_s].parent_reflection = habtm_reflection
|
1604
1830
|
end
|
1605
1831
|
end
|
1606
1832
|
end
|