activerecord 3.2.22.5 → 4.2.11.3
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 +5 -5
- data/CHANGELOG.md +1632 -609
- data/MIT-LICENSE +1 -1
- data/README.rdoc +37 -41
- data/examples/performance.rb +31 -19
- data/examples/simple.rb +4 -4
- data/lib/active_record/aggregations.rb +56 -42
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -36
- data/lib/active_record/associations/association.rb +73 -55
- data/lib/active_record/associations/association_scope.rb +143 -82
- data/lib/active_record/associations/belongs_to_association.rb +65 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +125 -31
- data/lib/active_record/associations/builder/belongs_to.rb +89 -61
- 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 -51
- data/lib/active_record/associations/builder/singular_association.rb +23 -17
- data/lib/active_record/associations/collection_association.rb +251 -177
- data/lib/active_record/associations/collection_proxy.rb +963 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +113 -22
- data/lib/active_record/associations/has_many_through_association.rb +99 -39
- data/lib/active_record/associations/has_one_association.rb +43 -20
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +76 -107
- 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 +62 -33
- data/lib/active_record/associations/preloader.rb +101 -79
- data/lib/active_record/associations/singular_association.rb +29 -13
- data/lib/active_record/associations/through_association.rb +30 -16
- data/lib/active_record/associations.rb +463 -345
- data/lib/active_record/attribute.rb +163 -0
- data/lib/active_record/attribute_assignment.rb +142 -151
- 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 +137 -57
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +73 -106
- data/lib/active_record/attribute_methods/serialization.rb +44 -94
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
- data/lib/active_record/attribute_methods/write.rb +57 -44
- data/lib/active_record/attribute_methods.rb +301 -141
- 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 +246 -217
- data/lib/active_record/base.rb +70 -474
- 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 +396 -219
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
- 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 +261 -169
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
- data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
- data/lib/active_record/connection_adapters/column.rb +31 -245
- data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
- data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
- 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 +430 -999
- data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
- data/lib/active_record/connection_handling.rb +132 -0
- data/lib/active_record/core.rb +579 -0
- data/lib/active_record/counter_cache.rb +157 -105
- data/lib/active_record/dynamic_matchers.rb +119 -63
- data/lib/active_record/enum.rb +197 -0
- data/lib/active_record/errors.rb +94 -36
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +9 -5
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +302 -215
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +143 -70
- data/lib/active_record/integration.rb +65 -12
- 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 +73 -52
- data/lib/active_record/locking/pessimistic.rb +5 -5
- data/lib/active_record/log_subscriber.rb +24 -21
- data/lib/active_record/migration/command_recorder.rb +124 -32
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +511 -213
- data/lib/active_record/model_schema.rb +91 -117
- data/lib/active_record/nested_attributes.rb +184 -130
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +81 -0
- data/lib/active_record/persistence.rb +276 -117
- data/lib/active_record/query_cache.rb +19 -37
- data/lib/active_record/querying.rb +28 -18
- data/lib/active_record/railtie.rb +73 -40
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +4 -3
- data/lib/active_record/railties/databases.rake +141 -416
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +1 -4
- data/lib/active_record/reflection.rb +513 -154
- data/lib/active_record/relation/batches.rb +91 -43
- data/lib/active_record/relation/calculations.rb +199 -161
- data/lib/active_record/relation/delegation.rb +116 -25
- data/lib/active_record/relation/finder_methods.rb +362 -248
- 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 -43
- data/lib/active_record/relation/query_methods.rb +928 -167
- data/lib/active_record/relation/spawn_methods.rb +48 -149
- data/lib/active_record/relation.rb +352 -207
- data/lib/active_record/result.rb +101 -10
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +56 -59
- data/lib/active_record/schema.rb +19 -13
- data/lib/active_record/schema_dumper.rb +106 -63
- data/lib/active_record/schema_migration.rb +53 -0
- data/lib/active_record/scoping/default.rb +50 -57
- data/lib/active_record/scoping/named.rb +73 -109
- data/lib/active_record/scoping.rb +58 -123
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +12 -22
- data/lib/active_record/statement_cache.rb +111 -0
- data/lib/active_record/store.rb +168 -15
- 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 +23 -16
- data/lib/active_record/transactions.rb +125 -79
- 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 +24 -16
- data/lib/active_record/validations/presence.rb +67 -0
- data/lib/active_record/validations/uniqueness.rb +123 -64
- data/lib/active_record/validations.rb +36 -29
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +66 -46
- data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/migration.rb +11 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +101 -45
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,12 +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 '
|
4
|
+
require 'active_record/errors'
|
8
5
|
|
9
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
|
+
|
10
13
|
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
11
14
|
def initialize(reflection, associated_class = nil)
|
12
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})")
|
@@ -21,7 +24,7 @@ module ActiveRecord
|
|
21
24
|
|
22
25
|
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
23
26
|
def initialize(owner_class_name, reflection, source_reflection)
|
24
|
-
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.")
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -43,11 +46,17 @@ module ActiveRecord
|
|
43
46
|
end
|
44
47
|
end
|
45
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
|
+
|
46
55
|
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
|
47
56
|
def initialize(reflection)
|
48
57
|
through_reflection = reflection.through_reflection
|
49
58
|
source_reflection_names = reflection.source_reflection_names
|
50
|
-
source_associations = reflection.through_reflection.klass.
|
59
|
+
source_associations = reflection.through_reflection.klass._reflections.keys
|
51
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)}?")
|
52
61
|
end
|
53
62
|
end
|
@@ -76,21 +85,15 @@ module ActiveRecord
|
|
76
85
|
end
|
77
86
|
end
|
78
87
|
|
79
|
-
class HasAndBelongsToManyAssociationForeignKeyNeeded < ActiveRecordError #:nodoc:
|
80
|
-
def initialize(reflection)
|
81
|
-
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.")
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
88
|
class EagerLoadPolymorphicError < ActiveRecordError #:nodoc:
|
86
89
|
def initialize(reflection)
|
87
|
-
super("
|
90
|
+
super("Cannot eagerly load the polymorphic association #{reflection.name.inspect}")
|
88
91
|
end
|
89
92
|
end
|
90
93
|
|
91
94
|
class ReadOnlyAssociation < ActiveRecordError #:nodoc:
|
92
95
|
def initialize(reflection)
|
93
|
-
super("
|
96
|
+
super("Cannot add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.")
|
94
97
|
end
|
95
98
|
end
|
96
99
|
|
@@ -113,11 +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
121
|
|
118
122
|
autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
|
119
123
|
autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association'
|
120
|
-
autoload :HasAndBelongsToManyAssociation, 'active_record/associations/has_and_belongs_to_many_association'
|
121
124
|
autoload :HasManyAssociation, 'active_record/associations/has_many_association'
|
122
125
|
autoload :HasManyThroughAssociation, 'active_record/associations/has_many_through_association'
|
123
126
|
autoload :HasOneAssociation, 'active_record/associations/has_one_association'
|
@@ -140,7 +143,6 @@ module ActiveRecord
|
|
140
143
|
autoload :JoinDependency, 'active_record/associations/join_dependency'
|
141
144
|
autoload :AssociationScope, 'active_record/associations/association_scope'
|
142
145
|
autoload :AliasTracker, 'active_record/associations/alias_tracker'
|
143
|
-
autoload :JoinHelper, 'active_record/associations/join_helper'
|
144
146
|
end
|
145
147
|
|
146
148
|
# Clears out the association cache.
|
@@ -156,7 +158,7 @@ module ActiveRecord
|
|
156
158
|
association = association_instance_get(name)
|
157
159
|
|
158
160
|
if association.nil?
|
159
|
-
reflection
|
161
|
+
raise AssociationNotFoundError.new(self, name) unless reflection = self.class._reflect_on_association(name)
|
160
162
|
association = reflection.association_class.new(self, reflection)
|
161
163
|
association_instance_set(name, association)
|
162
164
|
end
|
@@ -167,7 +169,7 @@ module ActiveRecord
|
|
167
169
|
private
|
168
170
|
# Returns the specified association instance if it responds to :loaded?, nil otherwise.
|
169
171
|
def association_instance_get(name)
|
170
|
-
@association_cache[name
|
172
|
+
@association_cache[name]
|
171
173
|
end
|
172
174
|
|
173
175
|
# Set the specified association instance.
|
@@ -175,7 +177,7 @@ module ActiveRecord
|
|
175
177
|
@association_cache[name] = association
|
176
178
|
end
|
177
179
|
|
178
|
-
# 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
|
179
181
|
# foreign keys. They express relationships like "Project has one Project Manager"
|
180
182
|
# or "Project belongs to a Portfolio". Each macro adds a number of methods to the
|
181
183
|
# class which are specialized according to the collection or association symbol and the
|
@@ -194,30 +196,10 @@ module ActiveRecord
|
|
194
196
|
# * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
|
195
197
|
# * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
|
196
198
|
# * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
|
197
|
-
# <tt>Project#milestones.delete(milestone), Project#milestones.
|
199
|
+
# <tt>Project#milestones.delete(milestone), Project#milestones.destroy(milestone), Project#milestones.find(milestone_id),</tt>
|
198
200
|
# <tt>Project#milestones.build, Project#milestones.create</tt>
|
199
201
|
# * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
|
200
|
-
# <tt>Project#categories.delete(category1)</tt>
|
201
|
-
#
|
202
|
-
# === Overriding generated methods
|
203
|
-
#
|
204
|
-
# Association methods are generated in a module that is included into the model class,
|
205
|
-
# which allows you to easily override with your own methods and call the original
|
206
|
-
# generated method with +super+. For example:
|
207
|
-
#
|
208
|
-
# class Car < ActiveRecord::Base
|
209
|
-
# belongs_to :owner
|
210
|
-
# belongs_to :old_owner
|
211
|
-
# def owner=(new_owner)
|
212
|
-
# self.old_owner = self.owner
|
213
|
-
# super
|
214
|
-
# end
|
215
|
-
# end
|
216
|
-
#
|
217
|
-
# If your model class is <tt>Project</tt>, the module is
|
218
|
-
# named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
|
219
|
-
# included in the model class immediately after the (anonymous) generated attributes methods
|
220
|
-
# module, meaning an association will override the methods for an attribute with the same name.
|
202
|
+
# <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
|
221
203
|
#
|
222
204
|
# === A word of warning
|
223
205
|
#
|
@@ -227,12 +209,13 @@ module ActiveRecord
|
|
227
209
|
# For instance, +attributes+ and +connection+ would be bad choices for association names.
|
228
210
|
#
|
229
211
|
# == Auto-generated methods
|
212
|
+
# See also Instance Public methods below for more details.
|
230
213
|
#
|
231
214
|
# === Singular associations (one-to-one)
|
232
215
|
# | | belongs_to |
|
233
216
|
# generated methods | belongs_to | :polymorphic | has_one
|
234
217
|
# ----------------------------------+------------+--------------+---------
|
235
|
-
# other
|
218
|
+
# other(force_reload=false) | X | X | X
|
236
219
|
# other=(other) | X | X | X
|
237
220
|
# build_other(attributes={}) | X | | X
|
238
221
|
# create_other(attributes={}) | X | | X
|
@@ -242,7 +225,7 @@ module ActiveRecord
|
|
242
225
|
# | | | has_many
|
243
226
|
# generated methods | habtm | has_many | :through
|
244
227
|
# ----------------------------------+-------+----------+----------
|
245
|
-
# others
|
228
|
+
# others(force_reload=false) | X | X | X
|
246
229
|
# others=(other,other,...) | X | X | X
|
247
230
|
# other_ids | X | X | X
|
248
231
|
# other_ids=(id,id,...) | X | X | X
|
@@ -255,17 +238,39 @@ module ActiveRecord
|
|
255
238
|
# others.size | X | X | X
|
256
239
|
# others.length | X | X | X
|
257
240
|
# others.count | X | X | X
|
258
|
-
# others.sum(args
|
241
|
+
# others.sum(*args) | X | X | X
|
259
242
|
# others.empty? | X | X | X
|
260
243
|
# others.clear | X | X | X
|
261
244
|
# others.delete(other,other,...) | X | X | X
|
262
245
|
# others.delete_all | X | X | X
|
246
|
+
# others.destroy(other,other,...) | X | X | X
|
263
247
|
# others.destroy_all | X | X | X
|
264
248
|
# others.find(*args) | X | X | X
|
265
249
|
# others.exists? | X | X | X
|
250
|
+
# others.distinct | X | X | X
|
266
251
|
# others.uniq | X | X | X
|
267
252
|
# others.reset | X | X | X
|
268
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
|
+
#
|
269
274
|
# == Cardinality and associations
|
270
275
|
#
|
271
276
|
# Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
|
@@ -308,11 +313,11 @@ module ActiveRecord
|
|
308
313
|
# end
|
309
314
|
# class Programmer < ActiveRecord::Base
|
310
315
|
# has_many :assignments
|
311
|
-
# has_many :projects, :
|
316
|
+
# has_many :projects, through: :assignments
|
312
317
|
# end
|
313
318
|
# class Project < ActiveRecord::Base
|
314
319
|
# has_many :assignments
|
315
|
-
# has_many :programmers, :
|
320
|
+
# has_many :programmers, through: :assignments
|
316
321
|
# end
|
317
322
|
#
|
318
323
|
# For the second way, use +has_and_belongs_to_many+ in both models. This requires a join table
|
@@ -366,11 +371,11 @@ module ActiveRecord
|
|
366
371
|
# there is some special behavior you should be aware of, mostly involving the saving of
|
367
372
|
# associated objects.
|
368
373
|
#
|
369
|
-
# You can set the
|
374
|
+
# You can set the <tt>:autosave</tt> option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
|
370
375
|
# <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association. Setting it
|
371
376
|
# to +true+ will _always_ save the members, whereas setting it to +false+ will
|
372
|
-
# _never_ save the members. More details about
|
373
|
-
#
|
377
|
+
# _never_ save the members. More details about <tt>:autosave</tt> option is available at
|
378
|
+
# AutosaveAssociation.
|
374
379
|
#
|
375
380
|
# === One-to-one associations
|
376
381
|
#
|
@@ -401,14 +406,39 @@ module ActiveRecord
|
|
401
406
|
# * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically
|
402
407
|
# saved when the parent is saved.
|
403
408
|
#
|
404
|
-
#
|
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
|
405
435
|
#
|
406
436
|
# Similar to the normal callbacks that hook into the life cycle of an Active Record object,
|
407
437
|
# you can also define callbacks that get triggered when you add an object to or remove an
|
408
438
|
# object from an association collection.
|
409
439
|
#
|
410
440
|
# class Project
|
411
|
-
# has_and_belongs_to_many :developers, :
|
441
|
+
# has_and_belongs_to_many :developers, after_add: :evaluate_velocity
|
412
442
|
#
|
413
443
|
# def evaluate_velocity(developer)
|
414
444
|
# ...
|
@@ -419,16 +449,18 @@ module ActiveRecord
|
|
419
449
|
#
|
420
450
|
# class Project
|
421
451
|
# has_and_belongs_to_many :developers,
|
422
|
-
# :
|
452
|
+
# after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
|
423
453
|
# end
|
424
454
|
#
|
425
455
|
# Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
|
426
456
|
#
|
427
|
-
#
|
428
|
-
# added to the collection.
|
429
|
-
#
|
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.
|
430
462
|
#
|
431
|
-
#
|
463
|
+
# == Association extensions
|
432
464
|
#
|
433
465
|
# The proxy objects that control the access to associations can be extended through anonymous
|
434
466
|
# modules. This is especially beneficial for adding new finders, creators, and other
|
@@ -438,7 +470,7 @@ module ActiveRecord
|
|
438
470
|
# has_many :people do
|
439
471
|
# def find_or_create_by_name(name)
|
440
472
|
# first_name, last_name = name.split(" ", 2)
|
441
|
-
#
|
473
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
442
474
|
# end
|
443
475
|
# end
|
444
476
|
# end
|
@@ -453,25 +485,16 @@ module ActiveRecord
|
|
453
485
|
# module FindOrCreateByNameExtension
|
454
486
|
# def find_or_create_by_name(name)
|
455
487
|
# first_name, last_name = name.split(" ", 2)
|
456
|
-
#
|
488
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
457
489
|
# end
|
458
490
|
# end
|
459
491
|
#
|
460
492
|
# class Account < ActiveRecord::Base
|
461
|
-
# has_many :people,
|
493
|
+
# has_many :people, -> { extending FindOrCreateByNameExtension }
|
462
494
|
# end
|
463
495
|
#
|
464
496
|
# class Company < ActiveRecord::Base
|
465
|
-
# has_many :people,
|
466
|
-
# end
|
467
|
-
#
|
468
|
-
# If you need to use multiple named extension modules, you can specify an array of modules
|
469
|
-
# with the <tt>:extend</tt> option.
|
470
|
-
# In the case of name conflicts between methods in the modules, methods in modules later
|
471
|
-
# in the array supercede those earlier in the array.
|
472
|
-
#
|
473
|
-
# class Account < ActiveRecord::Base
|
474
|
-
# has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
|
497
|
+
# has_many :people, -> { extending FindOrCreateByNameExtension }
|
475
498
|
# end
|
476
499
|
#
|
477
500
|
# Some extensions can only be made to work with knowledge of the association's internals.
|
@@ -489,7 +512,7 @@ module ActiveRecord
|
|
489
512
|
# the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside
|
490
513
|
# association extensions.
|
491
514
|
#
|
492
|
-
#
|
515
|
+
# == Association Join Models
|
493
516
|
#
|
494
517
|
# Has Many associations can be configured with the <tt>:through</tt> option to use an
|
495
518
|
# explicit join model to retrieve the data. This operates similarly to a
|
@@ -498,7 +521,7 @@ module ActiveRecord
|
|
498
521
|
#
|
499
522
|
# class Author < ActiveRecord::Base
|
500
523
|
# has_many :authorships
|
501
|
-
# has_many :books, :
|
524
|
+
# has_many :books, through: :authorships
|
502
525
|
# end
|
503
526
|
#
|
504
527
|
# class Authorship < ActiveRecord::Base
|
@@ -514,7 +537,7 @@ module ActiveRecord
|
|
514
537
|
#
|
515
538
|
# class Firm < ActiveRecord::Base
|
516
539
|
# has_many :clients
|
517
|
-
# has_many :invoices, :
|
540
|
+
# has_many :invoices, through: :clients
|
518
541
|
# end
|
519
542
|
#
|
520
543
|
# class Client < ActiveRecord::Base
|
@@ -527,14 +550,14 @@ module ActiveRecord
|
|
527
550
|
# end
|
528
551
|
#
|
529
552
|
# @firm = Firm.first
|
530
|
-
# @firm.clients.
|
531
|
-
# @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
|
532
555
|
#
|
533
556
|
# Similarly you can go through a +has_one+ association on the join model:
|
534
557
|
#
|
535
558
|
# class Group < ActiveRecord::Base
|
536
559
|
# has_many :users
|
537
|
-
# has_many :avatars, :
|
560
|
+
# has_many :avatars, through: :users
|
538
561
|
# end
|
539
562
|
#
|
540
563
|
# class User < ActiveRecord::Base
|
@@ -547,7 +570,7 @@ module ActiveRecord
|
|
547
570
|
# end
|
548
571
|
#
|
549
572
|
# @group = Group.first
|
550
|
-
# @group.users.collect { |u| u.avatar }.
|
573
|
+
# @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
|
551
574
|
# @group.avatars # selects all avatars by going through the User join model.
|
552
575
|
#
|
553
576
|
# An important caveat with going through +has_one+ or +has_many+ associations on the
|
@@ -557,12 +580,14 @@ module ActiveRecord
|
|
557
580
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
558
581
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
559
582
|
#
|
583
|
+
# == Setting Inverses
|
584
|
+
#
|
560
585
|
# If you are using a +belongs_to+ on the join model, it is a good idea to set the
|
561
586
|
# <tt>:inverse_of</tt> option on the +belongs_to+, which will mean that the following example
|
562
587
|
# works correctly (where <tt>tags</tt> is a +has_many+ <tt>:through</tt> association):
|
563
588
|
#
|
564
589
|
# @post = Post.first
|
565
|
-
# @tag = @post.tags.build :
|
590
|
+
# @tag = @post.tags.build name: "ruby"
|
566
591
|
# @tag.save
|
567
592
|
#
|
568
593
|
# The last line ought to save the through record (a <tt>Taggable</tt>). This will only work if the
|
@@ -570,18 +595,38 @@ module ActiveRecord
|
|
570
595
|
#
|
571
596
|
# class Taggable < ActiveRecord::Base
|
572
597
|
# belongs_to :post
|
573
|
-
# 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
|
574
619
|
# end
|
575
620
|
#
|
576
|
-
#
|
621
|
+
# == Nested \Associations
|
577
622
|
#
|
578
623
|
# You can actually specify *any* association with the <tt>:through</tt> option, including an
|
579
624
|
# association which has a <tt>:through</tt> option itself. For example:
|
580
625
|
#
|
581
626
|
# class Author < ActiveRecord::Base
|
582
627
|
# has_many :posts
|
583
|
-
# has_many :comments, :
|
584
|
-
# has_many :commenters, :
|
628
|
+
# has_many :comments, through: :posts
|
629
|
+
# has_many :commenters, through: :comments
|
585
630
|
# end
|
586
631
|
#
|
587
632
|
# class Post < ActiveRecord::Base
|
@@ -599,35 +644,35 @@ module ActiveRecord
|
|
599
644
|
#
|
600
645
|
# class Author < ActiveRecord::Base
|
601
646
|
# has_many :posts
|
602
|
-
# has_many :commenters, :
|
647
|
+
# has_many :commenters, through: :posts
|
603
648
|
# end
|
604
649
|
#
|
605
650
|
# class Post < ActiveRecord::Base
|
606
651
|
# has_many :comments
|
607
|
-
# has_many :commenters, :
|
652
|
+
# has_many :commenters, through: :comments
|
608
653
|
# end
|
609
654
|
#
|
610
655
|
# class Comment < ActiveRecord::Base
|
611
656
|
# belongs_to :commenter
|
612
657
|
# end
|
613
658
|
#
|
614
|
-
# 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
|
615
660
|
# is not enough information to know what modification to make. For example, if you tried to
|
616
661
|
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
|
617
662
|
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
|
618
663
|
#
|
619
|
-
#
|
664
|
+
# == Polymorphic \Associations
|
620
665
|
#
|
621
666
|
# Polymorphic associations on models are not restricted on what types of models they
|
622
667
|
# can be associated with. Rather, they specify an interface that a +has_many+ association
|
623
668
|
# must adhere to.
|
624
669
|
#
|
625
670
|
# class Asset < ActiveRecord::Base
|
626
|
-
# belongs_to :attachable, :
|
671
|
+
# belongs_to :attachable, polymorphic: true
|
627
672
|
# end
|
628
673
|
#
|
629
674
|
# class Post < ActiveRecord::Base
|
630
|
-
# has_many :assets, :
|
675
|
+
# has_many :assets, as: :attachable # The :as option specifies the polymorphic interface to use.
|
631
676
|
# end
|
632
677
|
#
|
633
678
|
# @asset.attachable = @post
|
@@ -643,17 +688,20 @@ module ActiveRecord
|
|
643
688
|
# and member posts that use the posts table for STI. In this case, there must be a +type+
|
644
689
|
# column in the posts table.
|
645
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
|
+
#
|
646
694
|
# class Asset < ActiveRecord::Base
|
647
|
-
# belongs_to :attachable, :
|
695
|
+
# belongs_to :attachable, polymorphic: true
|
648
696
|
#
|
649
|
-
# def attachable_type=(
|
650
|
-
# super(
|
697
|
+
# def attachable_type=(class_name)
|
698
|
+
# super(class_name.constantize.base_class.to_s)
|
651
699
|
# end
|
652
700
|
# end
|
653
701
|
#
|
654
702
|
# class Post < ActiveRecord::Base
|
655
|
-
# # because we store "Post" in attachable_type now :
|
656
|
-
# has_many :assets, :
|
703
|
+
# # because we store "Post" in attachable_type now dependent: :destroy will work
|
704
|
+
# has_many :assets, as: :attachable, dependent: :destroy
|
657
705
|
# end
|
658
706
|
#
|
659
707
|
# class GuestPost < Post
|
@@ -678,9 +726,9 @@ module ActiveRecord
|
|
678
726
|
# == Eager loading of associations
|
679
727
|
#
|
680
728
|
# Eager loading is a way to find objects of a certain class and a number of named associations.
|
681
|
-
#
|
729
|
+
# It is one of the easiest ways to prevent the dreaded N+1 problem in which fetching 100
|
682
730
|
# posts that each need to display their author triggers 101 database queries. Through the
|
683
|
-
# use of eager loading, the
|
731
|
+
# use of eager loading, the number of queries will be reduced from 101 to 2.
|
684
732
|
#
|
685
733
|
# class Post < ActiveRecord::Base
|
686
734
|
# belongs_to :author
|
@@ -710,16 +758,16 @@ module ActiveRecord
|
|
710
758
|
# Post.includes(:author, :comments).each do |post|
|
711
759
|
#
|
712
760
|
# This will load all comments with a single query. This reduces the total number of queries
|
713
|
-
# to 3.
|
761
|
+
# to 3. In general, the number of queries will be 1 plus the number of associations
|
714
762
|
# named (except if some of the associations are polymorphic +belongs_to+ - see below).
|
715
763
|
#
|
716
764
|
# To include a deep hierarchy of associations, use a hash:
|
717
765
|
#
|
718
|
-
# Post.includes(:author, {:
|
766
|
+
# Post.includes(:author, { comments: { author: :gravatar } }).each do |post|
|
719
767
|
#
|
720
|
-
#
|
721
|
-
# You can mix and match
|
722
|
-
# 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.
|
723
771
|
#
|
724
772
|
# All of this power shouldn't fool you into thinking that you can pull out huge amounts
|
725
773
|
# of data with no performance penalty just because you've reduced the number of queries.
|
@@ -728,10 +776,10 @@ module ActiveRecord
|
|
728
776
|
# cut down on the number of queries in a situation as the one described above.
|
729
777
|
#
|
730
778
|
# Since only one table is loaded at a time, conditions or orders cannot reference tables
|
731
|
-
# other than the main one. If this is the case Active Record falls back to the previously
|
732
|
-
# used LEFT OUTER JOIN based strategy. For example
|
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:
|
733
781
|
#
|
734
|
-
# Post.includes([:author, :comments]).where(['comments.approved = ?', true])
|
782
|
+
# Post.includes([:author, :comments]).where(['comments.approved = ?', true])
|
735
783
|
#
|
736
784
|
# This will result in a single SQL query with joins along the lines of:
|
737
785
|
# <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
|
@@ -739,14 +787,19 @@ module ActiveRecord
|
|
739
787
|
# like this can have unintended consequences.
|
740
788
|
# In the above example posts with no approved comments are not returned at all, because
|
741
789
|
# the conditions apply to the SQL statement as a whole and not just to the association.
|
790
|
+
#
|
742
791
|
# You must disambiguate column references for this fallback to happen, for example
|
743
|
-
# <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'")
|
744
798
|
#
|
745
|
-
#
|
746
|
-
# to include 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:
|
747
800
|
#
|
748
801
|
# class Post < ActiveRecord::Base
|
749
|
-
# has_many :approved_comments,
|
802
|
+
# has_many :approved_comments, -> { where approved: true }, class_name: 'Comment'
|
750
803
|
# end
|
751
804
|
#
|
752
805
|
# Post.includes(:approved_comments)
|
@@ -758,18 +811,15 @@ module ActiveRecord
|
|
758
811
|
# returning all the associated objects:
|
759
812
|
#
|
760
813
|
# class Picture < ActiveRecord::Base
|
761
|
-
# has_many :most_recent_comments,
|
814
|
+
# has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment'
|
762
815
|
# end
|
763
816
|
#
|
764
817
|
# Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
|
765
818
|
#
|
766
|
-
# When eager loaded, conditions are interpolated in the context of the model class, not
|
767
|
-
# the model instance. Conditions are lazily interpolated before the actual model exists.
|
768
|
-
#
|
769
819
|
# Eager loading is supported with polymorphic associations.
|
770
820
|
#
|
771
821
|
# class Address < ActiveRecord::Base
|
772
|
-
# belongs_to :addressable, :
|
822
|
+
# belongs_to :addressable, polymorphic: true
|
773
823
|
# end
|
774
824
|
#
|
775
825
|
# A call that tries to eager load the addressable model
|
@@ -781,7 +831,7 @@ module ActiveRecord
|
|
781
831
|
# For example if all the addressables are either of class Person or Company then a total
|
782
832
|
# of 3 queries will be executed. The list of addressable types to load is determined on
|
783
833
|
# the back of the addresses loaded. This is not supported if Active Record has to fallback
|
784
|
-
# 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>.
|
785
835
|
# The reason is that the parent model's type is a column value so its corresponding table
|
786
836
|
# name cannot be put in the +FROM+/+JOIN+ clauses of that query.
|
787
837
|
#
|
@@ -803,10 +853,10 @@ module ActiveRecord
|
|
803
853
|
#
|
804
854
|
# TreeMixin.joins(:children)
|
805
855
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
806
|
-
# TreeMixin.joins(:
|
856
|
+
# TreeMixin.joins(children: :parent)
|
807
857
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
808
858
|
# INNER JOIN parents_mixins ...
|
809
|
-
# TreeMixin.joins(:
|
859
|
+
# TreeMixin.joins(children: {parent: :children})
|
810
860
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
811
861
|
# INNER JOIN parents_mixins ...
|
812
862
|
# INNER JOIN mixins childrens_mixins_2
|
@@ -815,10 +865,10 @@ module ActiveRecord
|
|
815
865
|
#
|
816
866
|
# Post.joins(:categories)
|
817
867
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
818
|
-
# Post.joins(:
|
868
|
+
# Post.joins(categories: :posts)
|
819
869
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
820
870
|
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
821
|
-
# Post.joins(:
|
871
|
+
# Post.joins(categories: {posts: :categories})
|
822
872
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
823
873
|
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
824
874
|
# INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
|
@@ -843,8 +893,8 @@ module ActiveRecord
|
|
843
893
|
# module MyApplication
|
844
894
|
# module Business
|
845
895
|
# class Firm < ActiveRecord::Base
|
846
|
-
#
|
847
|
-
#
|
896
|
+
# has_many :clients
|
897
|
+
# end
|
848
898
|
#
|
849
899
|
# class Client < ActiveRecord::Base; end
|
850
900
|
# end
|
@@ -862,7 +912,7 @@ module ActiveRecord
|
|
862
912
|
#
|
863
913
|
# module Billing
|
864
914
|
# class Account < ActiveRecord::Base
|
865
|
-
# belongs_to :firm, :
|
915
|
+
# belongs_to :firm, class_name: "MyApplication::Business::Firm"
|
866
916
|
# end
|
867
917
|
# end
|
868
918
|
# end
|
@@ -904,16 +954,16 @@ module ActiveRecord
|
|
904
954
|
# example, if we changed our model definitions to:
|
905
955
|
#
|
906
956
|
# class Dungeon < ActiveRecord::Base
|
907
|
-
# has_many :traps, :
|
908
|
-
# has_one :evil_wizard, :
|
957
|
+
# has_many :traps, inverse_of: :dungeon
|
958
|
+
# has_one :evil_wizard, inverse_of: :dungeon
|
909
959
|
# end
|
910
960
|
#
|
911
961
|
# class Trap < ActiveRecord::Base
|
912
|
-
# belongs_to :dungeon, :
|
962
|
+
# belongs_to :dungeon, inverse_of: :traps
|
913
963
|
# end
|
914
964
|
#
|
915
965
|
# class EvilWizard < ActiveRecord::Base
|
916
|
-
# belongs_to :dungeon, :
|
966
|
+
# belongs_to :dungeon, inverse_of: :evil_wizard
|
917
967
|
# end
|
918
968
|
#
|
919
969
|
# Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same
|
@@ -936,13 +986,19 @@ module ActiveRecord
|
|
936
986
|
# For example:
|
937
987
|
#
|
938
988
|
# class Author
|
939
|
-
# has_many :posts, :
|
989
|
+
# has_many :posts, dependent: :destroy
|
940
990
|
# end
|
941
991
|
# Author.find(1).destroy # => Will destroy all of the author's posts, too
|
942
992
|
#
|
943
993
|
# The <tt>:dependent</tt> option can have different values which specify how the deletion
|
944
994
|
# is done. For more information, see the documentation for this option on the different
|
945
|
-
# 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.
|
946
1002
|
#
|
947
1003
|
# === Delete or destroy?
|
948
1004
|
#
|
@@ -952,11 +1008,11 @@ module ActiveRecord
|
|
952
1008
|
# For +has_and_belongs_to_many+, <tt>delete</tt> and <tt>destroy</tt> are the same: they
|
953
1009
|
# cause the records in the join table to be removed.
|
954
1010
|
#
|
955
|
-
# For +has_many+, <tt>destroy</tt> will always call the <tt>destroy</tt> method of the
|
956
|
-
# 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
|
957
1013
|
# do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
|
958
1014
|
# if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
|
959
|
-
# The default strategy is
|
1015
|
+
# The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for
|
960
1016
|
# +has_many+ <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete
|
961
1017
|
# the join records, without running their callbacks).
|
962
1018
|
#
|
@@ -974,7 +1030,7 @@ module ActiveRecord
|
|
974
1030
|
# associated objects themselves. So with +has_and_belongs_to_many+ and +has_many+
|
975
1031
|
# <tt>:through</tt>, the join records will be deleted, but the associated records won't.
|
976
1032
|
#
|
977
|
-
# 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>
|
978
1034
|
# you would want the 'food' tag to be unlinked from the post, rather than for the tag itself
|
979
1035
|
# to be removed from the database.
|
980
1036
|
#
|
@@ -1005,21 +1061,30 @@ module ActiveRecord
|
|
1005
1061
|
# Specifies a one-to-many association. The following methods for retrieval and query of
|
1006
1062
|
# collections of associated objects will be added:
|
1007
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
|
+
#
|
1008
1067
|
# [collection(force_reload = false)]
|
1009
1068
|
# Returns an array of all the associated objects.
|
1010
1069
|
# An empty array is returned if none are found.
|
1011
1070
|
# [collection<<(object, ...)]
|
1012
1071
|
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
|
1013
|
-
# Note that this operation instantly fires update
|
1014
|
-
# parent object.
|
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.
|
1015
1074
|
# [collection.delete(object, ...)]
|
1016
1075
|
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
|
1017
|
-
# Objects will be in addition destroyed if they're associated with <tt
|
1018
|
-
# and deleted if they're associated with <tt
|
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>.
|
1019
1078
|
#
|
1020
1079
|
# If the <tt>:through</tt> option is used, then the join records are deleted (rather than
|
1021
|
-
# nullified) by default, but you can specify <tt
|
1022
|
-
# <tt
|
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.
|
1023
1088
|
# [collection=objects]
|
1024
1089
|
# Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
|
1025
1090
|
# option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
|
@@ -1031,8 +1096,8 @@ module ActiveRecord
|
|
1031
1096
|
# method loads the models and calls <tt>collection=</tt>. See above.
|
1032
1097
|
# [collection.clear]
|
1033
1098
|
# Removes every object from the collection. This destroys the associated objects if they
|
1034
|
-
# are associated with <tt
|
1035
|
-
# 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+.
|
1036
1101
|
# If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
|
1037
1102
|
# Join models are directly deleted.
|
1038
1103
|
# [collection.empty?]
|
@@ -1040,10 +1105,10 @@ module ActiveRecord
|
|
1040
1105
|
# [collection.size]
|
1041
1106
|
# Returns the number of associated objects.
|
1042
1107
|
# [collection.find(...)]
|
1043
|
-
# 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>.
|
1044
1109
|
# [collection.exists?(...)]
|
1045
1110
|
# Checks whether an associated object with the given conditions exists.
|
1046
|
-
# Uses the same rules as ActiveRecord::Base.exists
|
1111
|
+
# Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>.
|
1047
1112
|
# [collection.build(attributes = {}, ...)]
|
1048
1113
|
# Returns one or more new objects of the collection type that have been instantiated
|
1049
1114
|
# with +attributes+ and linked to this object through a foreign key, but have not yet
|
@@ -1053,27 +1118,54 @@ module ActiveRecord
|
|
1053
1118
|
# with +attributes+, linked to this object through a foreign key, and that has already
|
1054
1119
|
# been saved (if it passed the validation). *Note*: This only works if the base model
|
1055
1120
|
# already exists in the DB, not if it is a new (unsaved) record!
|
1056
|
-
#
|
1057
|
-
#
|
1058
|
-
#
|
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.
|
1059
1124
|
#
|
1060
1125
|
# === Example
|
1061
1126
|
#
|
1062
|
-
#
|
1063
|
-
# * <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>)
|
1064
1129
|
# * <tt>Firm#clients<<</tt>
|
1065
1130
|
# * <tt>Firm#clients.delete</tt>
|
1131
|
+
# * <tt>Firm#clients.destroy</tt>
|
1066
1132
|
# * <tt>Firm#clients=</tt>
|
1067
1133
|
# * <tt>Firm#client_ids</tt>
|
1068
1134
|
# * <tt>Firm#client_ids=</tt>
|
1069
1135
|
# * <tt>Firm#clients.clear</tt>
|
1070
1136
|
# * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
|
1071
1137
|
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
|
1072
|
-
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.
|
1073
|
-
# * <tt>Firm#clients.exists?(:
|
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>)
|
1074
1140
|
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
|
1075
1141
|
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
|
1076
|
-
#
|
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
|
1077
1169
|
#
|
1078
1170
|
# === Options
|
1079
1171
|
# [:class_name]
|
@@ -1081,60 +1173,37 @@ module ActiveRecord
|
|
1081
1173
|
# from the association name. So <tt>has_many :products</tt> will by default be linked
|
1082
1174
|
# to the Product class, but if the real class name is SpecialProduct, you'll have to
|
1083
1175
|
# specify it with this option.
|
1084
|
-
# [:conditions]
|
1085
|
-
# Specify the conditions that the associated objects must meet in order to be included as a +WHERE+
|
1086
|
-
# SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. Record creations from
|
1087
|
-
# the association are scoped if a hash is used.
|
1088
|
-
# <tt>has_many :posts, :conditions => {:published => true}</tt> will create published
|
1089
|
-
# posts with <tt>@blog.posts.create</tt> or <tt>@blog.posts.build</tt>.
|
1090
|
-
# [:order]
|
1091
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1092
|
-
# such as <tt>last_name, first_name DESC</tt>.
|
1093
1176
|
# [:foreign_key]
|
1094
1177
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1095
1178
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+
|
1096
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>.
|
1097
1186
|
# [:primary_key]
|
1098
|
-
# Specify the
|
1187
|
+
# Specify the name of the column to use as the primary key for the association. By default this is +id+.
|
1099
1188
|
# [:dependent]
|
1100
|
-
#
|
1101
|
-
#
|
1102
|
-
#
|
1103
|
-
#
|
1104
|
-
# <tt>:
|
1105
|
-
#
|
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.
|
1106
1200
|
#
|
1107
1201
|
# If using with the <tt>:through</tt> option, the association on the join model must be
|
1108
1202
|
# a +belongs_to+, and the records which get deleted are the join records, rather than
|
1109
1203
|
# the associated records.
|
1110
|
-
#
|
1111
|
-
#
|
1112
|
-
#
|
1113
|
-
# associations that depend on multiple tables. May be supplied as a string or a proc where interpolation is
|
1114
|
-
# required. Note: When this option is used, +find_in_collection+
|
1115
|
-
# is _not_ added.
|
1116
|
-
# [:counter_sql]
|
1117
|
-
# Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
|
1118
|
-
# specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
|
1119
|
-
# replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
|
1120
|
-
# [:extend]
|
1121
|
-
# Specify a named module for extending the proxy. See "Association extensions".
|
1122
|
-
# [:include]
|
1123
|
-
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
1124
|
-
# [:group]
|
1125
|
-
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
1126
|
-
# [:having]
|
1127
|
-
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt>
|
1128
|
-
# returns. Uses the <tt>HAVING</tt> SQL-clause.
|
1129
|
-
# [:limit]
|
1130
|
-
# An integer determining the limit on the number of rows that should be returned.
|
1131
|
-
# [:offset]
|
1132
|
-
# An integer determining the offset from where the rows should be fetched. So at 5,
|
1133
|
-
# it would skip the first 4 rows.
|
1134
|
-
# [:select]
|
1135
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if
|
1136
|
-
# you, for example, want to do a join but not include the joined columns. Do not forget
|
1137
|
-
# to include the primary and foreign keys, otherwise it will raise an error.
|
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.
|
1138
1207
|
# [:as]
|
1139
1208
|
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
|
1140
1209
|
# [:through]
|
@@ -1156,21 +1225,21 @@ module ActiveRecord
|
|
1156
1225
|
# [:source]
|
1157
1226
|
# Specifies the source association name used by <tt>has_many :through</tt> queries.
|
1158
1227
|
# Only use it if the name cannot be inferred from the association.
|
1159
|
-
# <tt>has_many :subscribers, :
|
1228
|
+
# <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
|
1160
1229
|
# <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
|
1161
1230
|
# [:source_type]
|
1162
1231
|
# Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
|
1163
1232
|
# association is a polymorphic +belongs_to+.
|
1164
|
-
# [:uniq]
|
1165
|
-
# If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
|
1166
|
-
# [:readonly]
|
1167
|
-
# If true, all the associated objects are readonly through the association.
|
1168
1233
|
# [:validate]
|
1169
1234
|
# If +false+, don't validate the associated objects when saving the parent object. true by default.
|
1170
1235
|
# [:autosave]
|
1171
1236
|
# If true, always save the associated objects or destroy them if marked for destruction,
|
1172
1237
|
# when saving the parent object. If false, never save or destroy the associated objects.
|
1173
|
-
# By default, only save associated objects that are new records.
|
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>.
|
1174
1243
|
# [:inverse_of]
|
1175
1244
|
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
|
1176
1245
|
# that is the inverse of this <tt>has_many</tt> association. Does not work in combination
|
@@ -1178,38 +1247,35 @@ module ActiveRecord
|
|
1178
1247
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1179
1248
|
#
|
1180
1249
|
# Option examples:
|
1181
|
-
# has_many :comments,
|
1182
|
-
# has_many :comments,
|
1183
|
-
# has_many :people,
|
1184
|
-
# has_many :tracks,
|
1185
|
-
# has_many :comments, :
|
1186
|
-
# has_many :tags, :
|
1187
|
-
# has_many :reports,
|
1188
|
-
# has_many :subscribers, :
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
# FROM people p, post_subscriptions ps
|
1193
|
-
# WHERE ps.post_id = #{id} AND ps.person_id = p.id
|
1194
|
-
# ORDER BY p.first_name
|
1195
|
-
# }
|
1196
|
-
# }
|
1197
|
-
def has_many(name, options = {}, &extension)
|
1198
|
-
Builder::HasMany.build(self, name, options, &extension)
|
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
|
1199
1261
|
end
|
1200
1262
|
|
1201
1263
|
# Specifies a one-to-one association with another class. This method should only be used
|
1202
1264
|
# if the other class contains the foreign key. If the current class contains the foreign key,
|
1203
1265
|
# then you should use +belongs_to+ instead. See also ActiveRecord::Associations::ClassMethods's overview
|
1204
|
-
# 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+.
|
1205
1267
|
#
|
1206
1268
|
# The following methods for retrieval and query of a single associated object will be added:
|
1207
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
|
+
#
|
1208
1273
|
# [association(force_reload = false)]
|
1209
1274
|
# Returns the associated object. +nil+ is returned if none is found.
|
1210
1275
|
# [association=(associate)]
|
1211
1276
|
# Assigns the associate object, extracts the primary key, sets it as the foreign key,
|
1212
|
-
# 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.
|
1213
1279
|
# [build_association(attributes = {})]
|
1214
1280
|
# Returns a new object of the associated type that has been instantiated
|
1215
1281
|
# with +attributes+ and linked to this object through a foreign key, but has not
|
@@ -1222,55 +1288,58 @@ module ActiveRecord
|
|
1222
1288
|
# Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
|
1223
1289
|
# if the record is invalid.
|
1224
1290
|
#
|
1225
|
-
# (+association+ is replaced with the symbol passed as the first argument, so
|
1226
|
-
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.)
|
1227
|
-
#
|
1228
1291
|
# === Example
|
1229
1292
|
#
|
1230
1293
|
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
|
1231
|
-
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.
|
1294
|
+
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
|
1232
1295
|
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
|
1233
1296
|
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
|
1234
1297
|
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
|
1235
1298
|
# * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
|
1236
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
|
+
#
|
1237
1311
|
# === Options
|
1238
1312
|
#
|
1239
|
-
# 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.
|
1240
1314
|
#
|
1241
1315
|
# Options are:
|
1242
1316
|
# [:class_name]
|
1243
1317
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
1244
1318
|
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
|
1245
1319
|
# if the real class name is Person, you'll have to specify it with this option.
|
1246
|
-
# [:conditions]
|
1247
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1248
|
-
# SQL fragment, such as <tt>rank = 5</tt>. Record creation from the association is scoped if a hash
|
1249
|
-
# is used. <tt>has_one :account, :conditions => {:enabled => true}</tt> will create
|
1250
|
-
# an enabled account with <tt>@company.create_account</tt> or <tt>@company.build_account</tt>.
|
1251
|
-
# [:order]
|
1252
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1253
|
-
# such as <tt>last_name, first_name DESC</tt>.
|
1254
1320
|
# [:dependent]
|
1255
|
-
#
|
1256
|
-
#
|
1257
|
-
#
|
1258
|
-
#
|
1259
|
-
# <tt
|
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
|
1260
1329
|
# [:foreign_key]
|
1261
1330
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1262
1331
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association
|
1263
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>.
|
1264
1339
|
# [:primary_key]
|
1265
1340
|
# Specify the method that returns the primary key used for the association. By default this is +id+.
|
1266
|
-
# [:include]
|
1267
|
-
# Specify second-order associations that should be eager loaded when this object is loaded.
|
1268
1341
|
# [:as]
|
1269
1342
|
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
|
1270
|
-
# [:select]
|
1271
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example,
|
1272
|
-
# you want to do a join but not include the joined columns. Do not forget to include the
|
1273
|
-
# primary and foreign keys, otherwise it will raise an error.
|
1274
1343
|
# [:through]
|
1275
1344
|
# Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
|
1276
1345
|
# <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
|
@@ -1279,37 +1348,43 @@ module ActiveRecord
|
|
1279
1348
|
# [:source]
|
1280
1349
|
# Specifies the source association name used by <tt>has_one :through</tt> queries.
|
1281
1350
|
# Only use it if the name cannot be inferred from the association.
|
1282
|
-
# <tt>has_one :favorite, :
|
1351
|
+
# <tt>has_one :favorite, through: :favorites</tt> will look for a
|
1283
1352
|
# <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
|
1284
1353
|
# [:source_type]
|
1285
1354
|
# Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
|
1286
1355
|
# association is a polymorphic +belongs_to+.
|
1287
|
-
# [:readonly]
|
1288
|
-
# If true, the associated object is readonly through the association.
|
1289
1356
|
# [:validate]
|
1290
1357
|
# If +false+, don't validate the associated object when saving the parent object. +false+ by default.
|
1291
1358
|
# [:autosave]
|
1292
1359
|
# If true, always save the associated object or destroy it if marked for destruction,
|
1293
1360
|
# when saving the parent object. If false, never save or destroy the associated object.
|
1294
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>.
|
1295
1364
|
# [:inverse_of]
|
1296
1365
|
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
|
1297
1366
|
# that is the inverse of this <tt>has_one</tt> association. Does not work in combination
|
1298
1367
|
# with <tt>:through</tt> or <tt>:as</tt> options.
|
1299
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.
|
1300
1373
|
#
|
1301
1374
|
# Option examples:
|
1302
|
-
# has_one :credit_card, :
|
1303
|
-
# 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
|
1304
1377
|
# # key value to NULL rather than destroying it
|
1305
|
-
# has_one :last_comment,
|
1306
|
-
# has_one :project_manager,
|
1307
|
-
# has_one :attachment, :
|
1308
|
-
# has_one :boss,
|
1309
|
-
# has_one :club, :
|
1310
|
-
# has_one :primary_address,
|
1311
|
-
|
1312
|
-
|
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
|
1313
1388
|
end
|
1314
1389
|
|
1315
1390
|
# Specifies a one-to-one association with another class. This method should only be used
|
@@ -1320,6 +1395,9 @@ module ActiveRecord
|
|
1320
1395
|
# Methods will be added for retrieval and query for a single associated object, for which
|
1321
1396
|
# this object holds an id:
|
1322
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
|
+
#
|
1323
1401
|
# [association(force_reload = false)]
|
1324
1402
|
# Returns the associated object. +nil+ is returned if none is found.
|
1325
1403
|
# [association=(associate)]
|
@@ -1335,9 +1413,6 @@ module ActiveRecord
|
|
1335
1413
|
# Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
|
1336
1414
|
# if the record is invalid.
|
1337
1415
|
#
|
1338
|
-
# (+association+ is replaced with the symbol passed as the first argument, so
|
1339
|
-
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.)
|
1340
|
-
#
|
1341
1416
|
# === Example
|
1342
1417
|
#
|
1343
1418
|
# A Post class declares <tt>belongs_to :author</tt>, which will add:
|
@@ -1346,7 +1421,18 @@ module ActiveRecord
|
|
1346
1421
|
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
|
1347
1422
|
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
|
1348
1423
|
# * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
|
1349
|
-
# The declaration can also include an options hash to specialize the behavior of the association.
|
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) }
|
1350
1436
|
#
|
1351
1437
|
# === Options
|
1352
1438
|
#
|
@@ -1354,23 +1440,16 @@ module ActiveRecord
|
|
1354
1440
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
1355
1441
|
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
|
1356
1442
|
# if the real class name is Person, you'll have to specify it with this option.
|
1357
|
-
# [:conditions]
|
1358
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1359
|
-
# SQL fragment, such as <tt>authorized = 1</tt>.
|
1360
|
-
# [:select]
|
1361
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed
|
1362
|
-
# if, for example, you want to do a join but not include the joined columns. Do not
|
1363
|
-
# forget to include the primary and foreign keys, otherwise it will raise an error.
|
1364
1443
|
# [:foreign_key]
|
1365
1444
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1366
1445
|
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
|
1367
1446
|
# association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
|
1368
|
-
# <tt>belongs_to :favorite_person, :
|
1447
|
+
# <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key
|
1369
1448
|
# of "favorite_person_id".
|
1370
1449
|
# [:foreign_type]
|
1371
1450
|
# Specify the column used to store the associated object's type, if this is a polymorphic
|
1372
1451
|
# association. By default this is guessed to be the name of the association with a "_type"
|
1373
|
-
# suffix. So a class that defines a <tt>belongs_to :taggable, :
|
1452
|
+
# suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt>
|
1374
1453
|
# association will use "taggable_type" as the default <tt>:foreign_type</tt>.
|
1375
1454
|
# [:primary_key]
|
1376
1455
|
# Specify the method that returns the primary key of associated object used for the association.
|
@@ -1386,19 +1465,17 @@ module ActiveRecord
|
|
1386
1465
|
# and +decrement_counter+. The counter cache is incremented when an object of this
|
1387
1466
|
# class is created and decremented when it's destroyed. This requires that a column
|
1388
1467
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
1389
|
-
# is used on the associate class (such as a Post class)
|
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
|
1390
1471
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
1391
|
-
# option (e.g., <tt
|
1472
|
+
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
1392
1473
|
# Note: Specifying a counter cache will add it to that model's list of readonly attributes
|
1393
1474
|
# using +attr_readonly+.
|
1394
|
-
# [:include]
|
1395
|
-
# Specify second-order associations that should be eager loaded when this object is loaded.
|
1396
1475
|
# [:polymorphic]
|
1397
1476
|
# Specify this association is a polymorphic association by passing +true+.
|
1398
1477
|
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
1399
1478
|
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
1400
|
-
# [:readonly]
|
1401
|
-
# If true, the associated object is readonly through the association.
|
1402
1479
|
# [:validate]
|
1403
1480
|
# If +false+, don't validate the associated objects when saving the parent object. +false+ by default.
|
1404
1481
|
# [:autosave]
|
@@ -1406,8 +1483,10 @@ module ActiveRecord
|
|
1406
1483
|
# saving the parent object.
|
1407
1484
|
# If false, never save or destroy the associated object.
|
1408
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>.
|
1409
1488
|
# [:touch]
|
1410
|
-
# 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)
|
1411
1490
|
# when this record is either saved or destroyed. If you specify a symbol, that attribute
|
1412
1491
|
# will be updated with the current time in addition to the updated_at/on attribute.
|
1413
1492
|
# [:inverse_of]
|
@@ -1415,26 +1494,32 @@ module ActiveRecord
|
|
1415
1494
|
# object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
|
1416
1495
|
# combination with the <tt>:polymorphic</tt> options.
|
1417
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.
|
1418
1501
|
#
|
1419
1502
|
# Option examples:
|
1420
|
-
# belongs_to :firm, :
|
1421
|
-
# belongs_to :person, :
|
1422
|
-
# belongs_to :author, :
|
1423
|
-
# belongs_to :valid_coupon,
|
1424
|
-
#
|
1425
|
-
# belongs_to :attachable, :
|
1426
|
-
# belongs_to :project,
|
1427
|
-
# belongs_to :post, :
|
1428
|
-
# belongs_to :company, :
|
1429
|
-
# belongs_to :company, :
|
1430
|
-
|
1431
|
-
|
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
|
1432
1517
|
end
|
1433
1518
|
|
1434
1519
|
# Specifies a many-to-many relationship with another class. This associates two classes via an
|
1435
1520
|
# intermediate join table. Unless the join table is explicitly specified as an option, it is
|
1436
1521
|
# guessed using the lexical order of the class names. So a join between Developer and Project
|
1437
|
-
# will give the default join table name of "developers_projects" because "D"
|
1522
|
+
# will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically.
|
1438
1523
|
# Note that this precedence is calculated using the <tt><</tt> operator for String. This
|
1439
1524
|
# means that if the strings are of different lengths, and the strings are equal when compared
|
1440
1525
|
# up to the shortest length, then the longer string is considered of higher
|
@@ -1442,13 +1527,15 @@ module ActiveRecord
|
|
1442
1527
|
# to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
|
1443
1528
|
# but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
|
1444
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".
|
1445
1532
|
#
|
1446
1533
|
# The join table should not have a primary key or a model associated with it. You must manually generate the
|
1447
1534
|
# join table with a migration such as this:
|
1448
1535
|
#
|
1449
1536
|
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
|
1450
1537
|
# def change
|
1451
|
-
# create_table :developers_projects, :
|
1538
|
+
# create_table :developers_projects, id: false do |t|
|
1452
1539
|
# t.integer :developer_id
|
1453
1540
|
# t.integer :project_id
|
1454
1541
|
# end
|
@@ -1461,17 +1548,23 @@ module ActiveRecord
|
|
1461
1548
|
#
|
1462
1549
|
# Adds the following methods for retrieval and query:
|
1463
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
|
+
#
|
1464
1554
|
# [collection(force_reload = false)]
|
1465
1555
|
# Returns an array of all the associated objects.
|
1466
1556
|
# An empty array is returned if none are found.
|
1467
1557
|
# [collection<<(object, ...)]
|
1468
1558
|
# Adds one or more objects to the collection by creating associations in the join table
|
1469
1559
|
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
|
1470
|
-
# Note that this operation instantly fires update
|
1471
|
-
# parent object.
|
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.
|
1472
1562
|
# [collection.delete(object, ...)]
|
1473
1563
|
# Removes one or more objects from the collection by removing their associations from the join table.
|
1474
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.
|
1475
1568
|
# [collection=objects]
|
1476
1569
|
# Replaces the collection's content by deleting and adding objects as appropriate.
|
1477
1570
|
# [collection_singular_ids]
|
@@ -1487,10 +1580,10 @@ module ActiveRecord
|
|
1487
1580
|
# [collection.find(id)]
|
1488
1581
|
# Finds an associated object responding to the +id+ and that
|
1489
1582
|
# meets the condition that it has to be associated with this object.
|
1490
|
-
# Uses the same rules as ActiveRecord::Base.find
|
1583
|
+
# Uses the same rules as <tt>ActiveRecord::Base.find</tt>.
|
1491
1584
|
# [collection.exists?(...)]
|
1492
1585
|
# Checks whether an associated object with the given conditions exists.
|
1493
|
-
# Uses the same rules as ActiveRecord::Base.exists
|
1586
|
+
# Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>.
|
1494
1587
|
# [collection.build(attributes = {})]
|
1495
1588
|
# Returns a new object of the collection type that has been instantiated
|
1496
1589
|
# with +attributes+ and linked to this object through the join table, but has not yet been saved.
|
@@ -1499,15 +1592,13 @@ module ActiveRecord
|
|
1499
1592
|
# with +attributes+, linked to this object through the join table, and that has already been
|
1500
1593
|
# saved (if it passed the validation).
|
1501
1594
|
#
|
1502
|
-
# (+collection+ is replaced with the symbol passed as the first argument, so
|
1503
|
-
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.)
|
1504
|
-
#
|
1505
1595
|
# === Example
|
1506
1596
|
#
|
1507
1597
|
# A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
|
1508
1598
|
# * <tt>Developer#projects</tt>
|
1509
1599
|
# * <tt>Developer#projects<<</tt>
|
1510
1600
|
# * <tt>Developer#projects.delete</tt>
|
1601
|
+
# * <tt>Developer#projects.destroy</tt>
|
1511
1602
|
# * <tt>Developer#projects=</tt>
|
1512
1603
|
# * <tt>Developer#project_ids</tt>
|
1513
1604
|
# * <tt>Developer#project_ids=</tt>
|
@@ -1518,7 +1609,34 @@ module ActiveRecord
|
|
1518
1609
|
# * <tt>Developer#projects.exists?(...)</tt>
|
1519
1610
|
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
|
1520
1611
|
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
|
1521
|
-
# The declaration may include an options hash to specialize the behavior of the association.
|
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
|
1522
1640
|
#
|
1523
1641
|
# === Options
|
1524
1642
|
#
|
@@ -1540,47 +1658,6 @@ module ActiveRecord
|
|
1540
1658
|
# By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
|
1541
1659
|
# So if a Person class makes a +has_and_belongs_to_many+ association to Project,
|
1542
1660
|
# the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
|
1543
|
-
# [:conditions]
|
1544
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1545
|
-
# SQL fragment, such as <tt>authorized = 1</tt>. Record creations from the association are
|
1546
|
-
# scoped if a hash is used.
|
1547
|
-
# <tt>has_many :posts, :conditions => {:published => true}</tt> will create published posts with <tt>@blog.posts.create</tt>
|
1548
|
-
# or <tt>@blog.posts.build</tt>.
|
1549
|
-
# [:order]
|
1550
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1551
|
-
# such as <tt>last_name, first_name DESC</tt>
|
1552
|
-
# [:uniq]
|
1553
|
-
# If true, duplicate associated objects will be ignored by accessors and query methods.
|
1554
|
-
# [:finder_sql]
|
1555
|
-
# Overwrite the default generated SQL statement used to fetch the association with a manual statement
|
1556
|
-
# [:counter_sql]
|
1557
|
-
# Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
|
1558
|
-
# specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
|
1559
|
-
# replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
|
1560
|
-
# [:delete_sql]
|
1561
|
-
# Overwrite the default generated SQL statement used to remove links between the associated
|
1562
|
-
# classes with a manual statement.
|
1563
|
-
# [:insert_sql]
|
1564
|
-
# Overwrite the default generated SQL statement used to add links between the associated classes
|
1565
|
-
# with a manual statement.
|
1566
|
-
# [:extend]
|
1567
|
-
# Anonymous module for extending the proxy, see "Association extensions".
|
1568
|
-
# [:include]
|
1569
|
-
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
1570
|
-
# [:group]
|
1571
|
-
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
1572
|
-
# [:having]
|
1573
|
-
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns.
|
1574
|
-
# Uses the <tt>HAVING</tt> SQL-clause.
|
1575
|
-
# [:limit]
|
1576
|
-
# An integer determining the limit on the number of rows that should be returned.
|
1577
|
-
# [:offset]
|
1578
|
-
# An integer determining the offset from where the rows should be fetched. So at 5,
|
1579
|
-
# it would skip the first 4 rows.
|
1580
|
-
# [:select]
|
1581
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example,
|
1582
|
-
# you want to do a join but not include the joined columns. Do not forget to include the primary
|
1583
|
-
# and foreign keys, otherwise it will raise an error.
|
1584
1661
|
# [:readonly]
|
1585
1662
|
# If true, all the associated objects are readonly through the association.
|
1586
1663
|
# [:validate]
|
@@ -1591,16 +1668,57 @@ module ActiveRecord
|
|
1591
1668
|
# If false, never save or destroy the associated objects.
|
1592
1669
|
# By default, only save associated objects that are new records.
|
1593
1670
|
#
|
1671
|
+
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
|
1672
|
+
#
|
1594
1673
|
# Option examples:
|
1595
1674
|
# has_and_belongs_to_many :projects
|
1596
|
-
# has_and_belongs_to_many :projects,
|
1597
|
-
# has_and_belongs_to_many :nations, :
|
1598
|
-
# has_and_belongs_to_many :categories, :
|
1599
|
-
# has_and_belongs_to_many :categories,
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
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
|
1715
|
+
|
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
|
1719
|
+
|
1720
|
+
has_many name, scope, hm_options, &extension
|
1721
|
+
self._reflections[name.to_s].parent_reflection = [name.to_s, habtm_reflection]
|
1604
1722
|
end
|
1605
1723
|
end
|
1606
1724
|
end
|