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