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.

Files changed (236) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1632 -609
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +37 -41
  5. data/examples/performance.rb +31 -19
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +56 -42
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -36
  10. data/lib/active_record/associations/association.rb +73 -55
  11. data/lib/active_record/associations/association_scope.rb +143 -82
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +125 -31
  15. data/lib/active_record/associations/builder/belongs_to.rb +89 -61
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +23 -17
  21. data/lib/active_record/associations/collection_association.rb +251 -177
  22. data/lib/active_record/associations/collection_proxy.rb +963 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +113 -22
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -39
  26. data/lib/active_record/associations/has_one_association.rb +43 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -107
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +62 -33
  38. data/lib/active_record/associations/preloader.rb +101 -79
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +30 -16
  41. data/lib/active_record/associations.rb +463 -345
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +142 -151
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +137 -57
  47. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +73 -106
  50. data/lib/active_record/attribute_methods/serialization.rb +44 -94
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
  52. data/lib/active_record/attribute_methods/write.rb +57 -44
  53. data/lib/active_record/attribute_methods.rb +301 -141
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +246 -217
  58. data/lib/active_record/base.rb +70 -474
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +396 -219
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +261 -169
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
  75. data/lib/active_record/connection_adapters/column.rb +31 -245
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +430 -999
  114. data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +157 -105
  119. data/lib/active_record/dynamic_matchers.rb +119 -63
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +94 -36
  122. data/lib/active_record/explain.rb +15 -63
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +9 -5
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +302 -215
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +143 -70
  129. data/lib/active_record/integration.rb +65 -12
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +73 -52
  133. data/lib/active_record/locking/pessimistic.rb +5 -5
  134. data/lib/active_record/log_subscriber.rb +24 -21
  135. data/lib/active_record/migration/command_recorder.rb +124 -32
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +511 -213
  138. data/lib/active_record/model_schema.rb +91 -117
  139. data/lib/active_record/nested_attributes.rb +184 -130
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +276 -117
  143. data/lib/active_record/query_cache.rb +19 -37
  144. data/lib/active_record/querying.rb +28 -18
  145. data/lib/active_record/railtie.rb +73 -40
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +4 -3
  148. data/lib/active_record/railties/databases.rake +141 -416
  149. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  150. data/lib/active_record/readonly_attributes.rb +1 -4
  151. data/lib/active_record/reflection.rb +513 -154
  152. data/lib/active_record/relation/batches.rb +91 -43
  153. data/lib/active_record/relation/calculations.rb +199 -161
  154. data/lib/active_record/relation/delegation.rb +116 -25
  155. data/lib/active_record/relation/finder_methods.rb +362 -248
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -43
  160. data/lib/active_record/relation/query_methods.rb +928 -167
  161. data/lib/active_record/relation/spawn_methods.rb +48 -149
  162. data/lib/active_record/relation.rb +352 -207
  163. data/lib/active_record/result.rb +101 -10
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +56 -59
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +106 -63
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +50 -57
  170. data/lib/active_record/scoping/named.rb +73 -109
  171. data/lib/active_record/scoping.rb +58 -123
  172. data/lib/active_record/serialization.rb +6 -2
  173. data/lib/active_record/serializers/xml_serializer.rb +12 -22
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +168 -15
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +23 -16
  181. data/lib/active_record/transactions.rb +125 -79
  182. data/lib/active_record/type/big_integer.rb +13 -0
  183. data/lib/active_record/type/binary.rb +50 -0
  184. data/lib/active_record/type/boolean.rb +31 -0
  185. data/lib/active_record/type/date.rb +50 -0
  186. data/lib/active_record/type/date_time.rb +54 -0
  187. data/lib/active_record/type/decimal.rb +64 -0
  188. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  189. data/lib/active_record/type/decorator.rb +14 -0
  190. data/lib/active_record/type/float.rb +19 -0
  191. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  192. data/lib/active_record/type/integer.rb +59 -0
  193. data/lib/active_record/type/mutable.rb +16 -0
  194. data/lib/active_record/type/numeric.rb +36 -0
  195. data/lib/active_record/type/serialized.rb +62 -0
  196. data/lib/active_record/type/string.rb +40 -0
  197. data/lib/active_record/type/text.rb +11 -0
  198. data/lib/active_record/type/time.rb +26 -0
  199. data/lib/active_record/type/time_value.rb +38 -0
  200. data/lib/active_record/type/type_map.rb +64 -0
  201. data/lib/active_record/type/unsigned_integer.rb +15 -0
  202. data/lib/active_record/type/value.rb +110 -0
  203. data/lib/active_record/type.rb +23 -0
  204. data/lib/active_record/validations/associated.rb +24 -16
  205. data/lib/active_record/validations/presence.rb +67 -0
  206. data/lib/active_record/validations/uniqueness.rb +123 -64
  207. data/lib/active_record/validations.rb +36 -29
  208. data/lib/active_record/version.rb +5 -7
  209. data/lib/active_record.rb +66 -46
  210. data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
  211. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
  212. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  213. data/lib/rails/generators/active_record/migration.rb +11 -8
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
  215. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  216. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  217. data/lib/rails/generators/active_record.rb +3 -11
  218. metadata +101 -45
  219. data/examples/associations.png +0 -0
  220. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  221. data/lib/active_record/associations/join_helper.rb +0 -55
  222. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  223. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  226. data/lib/active_record/dynamic_finder_match.rb +0 -68
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/fixtures/file.rb +0 -65
  229. data/lib/active_record/identity_map.rb +0 -162
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -360
  232. data/lib/active_record/test_case.rb +0 -73
  233. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  234. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  235. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  236. 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 'active_support/core_ext/class/attribute'
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.reflect_on_all_associations.collect { |a| a.name.inspect }
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("Can not eagerly load the polymorphic association #{reflection.name.inspect}")
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("Can not add to a has_many :through association. Try adding to #{reflection.through_reflection.name.inspect}.")
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 = self.class.reflect_on_association(name)
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.to_sym]
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.find(milestone_id), Project#milestones.all(options),</tt>
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 | X | X | X
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 | X | X | X
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*,&block) | X | X | X
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, :through => :assignments
316
+ # has_many :projects, through: :assignments
312
317
  # end
313
318
  # class Project < ActiveRecord::Base
314
319
  # has_many :assignments
315
- # has_many :programmers, :through => :assignments
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 :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
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 :autosave option is available at
373
- # autosave_association.rb .
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
- # === Association callbacks
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, :after_add => :evaluate_velocity
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
- # :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
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
- # Should any of the +before_add+ callbacks throw an exception, the object does not get
428
- # added to the collection. Same with the +before_remove+ callbacks; if an exception is
429
- # thrown the object doesn't get removed.
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
- # === Association extensions
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
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
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
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
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, :extend => FindOrCreateByNameExtension
493
+ # has_many :people, -> { extending FindOrCreateByNameExtension }
462
494
  # end
463
495
  #
464
496
  # class Company < ActiveRecord::Base
465
- # has_many :people, :extend => FindOrCreateByNameExtension
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
- # === Association Join Models
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, :through => :authorships
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, :through => :clients
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.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm
531
- # @firm.invoices # selects all invoices by going through the Client join model
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, :through => :users
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 }.flatten # select all avatars for all users in the group
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 :name => "ruby"
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, :inverse_of => :taggings
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
- # === Nested Associations
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, :through => :posts
584
- # has_many :commenters, :through => :comments
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, :through => :posts
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, :through => :comments
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
- # === Polymorphic Associations
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, :polymorphic => true
671
+ # belongs_to :attachable, polymorphic: true
627
672
  # end
628
673
  #
629
674
  # class Post < ActiveRecord::Base
630
- # has_many :assets, :as => :attachable # The :as option specifies the polymorphic interface to use.
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, :polymorphic => true
695
+ # belongs_to :attachable, polymorphic: true
648
696
  #
649
- # def attachable_type=(sType)
650
- # super(sType.to_s.classify.constantize.base_class.to_s)
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 :dependent => :destroy will work
656
- # has_many :assets, :as => :attachable, :dependent => :destroy
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
- # This is one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100
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 101 queries can be reduced to 2.
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. More generally the number of queries will be 1 plus the number of associations
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, {:comments => {:author => :gravatar}}).each do |post|
766
+ # Post.includes(:author, { comments: { author: :gravatar } }).each do |post|
719
767
  #
720
- # That'll grab not only all the comments but all their authors and gravatar pictures.
721
- # You can mix and match symbols, arrays and hashes in any combination to describe the
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]).all
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>:order => "author.name DESC"</tt> will work but <tt>:order => "name DESC"</tt> will not.
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
- # If you do want eager load only some members of an association it is usually more natural
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, :class_name => 'Comment', :conditions => ['approved = ?', true]
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, :class_name => 'Comment', :order => 'id DESC', :limit => 10
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, :polymorphic => true
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(:children => :parent)
856
+ # TreeMixin.joins(children: :parent)
807
857
  # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
808
858
  # INNER JOIN parents_mixins ...
809
- # TreeMixin.joins(:children => {:parent => :children})
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(:categories => :posts)
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(:categories => {:posts => :categories})
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
- # has_many :clients
847
- # end
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, :class_name => "MyApplication::Business::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, :inverse_of => :dungeon
908
- # has_one :evil_wizard, :inverse_of => :dungeon
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, :inverse_of => :traps
962
+ # belongs_to :dungeon, inverse_of: :traps
913
963
  # end
914
964
  #
915
965
  # class EvilWizard < ActiveRecord::Base
916
- # belongs_to :dungeon, :inverse_of => :evil_wizard
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, :dependent => :destroy
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 <tt>:nullify</tt> (set the foreign keys to <tt>nil</tt>), except for
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.find_by_name('food'))</tt>
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 sql without waiting for the save or update call on the
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>:dependent => :destroy</tt>,
1018
- # and deleted if they're associated with <tt>:dependent => :delete_all</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>:dependent => :destroy</tt> or
1022
- # <tt>:dependent => :nullify</tt> to override this.
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>:dependent => :destroy</tt>, deletes them directly from the
1035
- # database if <tt>:dependent => :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
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
- # (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
1058
- # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
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
- # Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
1063
- # * <tt>Firm#clients</tt> (similar to <tt>Clients.all :conditions => ["firm_id = ?", id]</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.find(id, :conditions => "firm_id = #{id}")</tt>)
1073
- # * <tt>Firm#clients.exists?(:name => 'ACME')</tt> (similar to <tt>Client.exists?(:name => 'ACME', :firm_id => firm.id)</tt>)
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
- # The declaration can also include an options hash to specialize the behavior of the association.
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 method that returns the primary key used for the association. By default this is +id+.
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
- # If set to <tt>:destroy</tt> all the associated objects are destroyed
1101
- # alongside this object by calling their +destroy+ method. If set to <tt>:delete_all</tt> all associated
1102
- # objects are deleted *without* calling their +destroy+ method. If set to <tt>:nullify</tt> all associated
1103
- # objects' foreign keys are set to +NULL+ *without* calling their +save+ callbacks. If set to
1104
- # <tt>:restrict</tt> this object raises an <tt>ActiveRecord::DeleteRestrictionError</tt> exception and
1105
- # cannot be deleted if it has any associated objects.
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
- # [:finder_sql]
1112
- # Specify a complete SQL statement to fetch the association. This is a good way to go for complex
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, :through => :subscriptions</tt> will look for either <tt>:subscribers</tt> or
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, :order => "posted_on"
1182
- # has_many :comments, :include => :author
1183
- # has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
1184
- # has_many :tracks, :order => "position", :dependent => :destroy
1185
- # has_many :comments, :dependent => :nullify
1186
- # has_many :tags, :as => :taggable
1187
- # has_many :reports, :readonly => true
1188
- # has_many :subscribers, :through => :subscriptions, :source => :user
1189
- # has_many :subscribers, :class_name => "Person", :finder_sql => Proc.new {
1190
- # %Q{
1191
- # SELECT DISTINCT *
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.first(:conditions => "account_id = #{id}")</tt>)
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
- # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
1256
- # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
1257
- # If set to <tt>:nullify</tt>, the associated object's foreign key is set to +NULL+.
1258
- # Also, association is assigned. If set to <tt>:restrict</tt> this object raises an
1259
- # <tt>ActiveRecord::DeleteRestrictionError</tt> exception and cannot be deleted if it has any associated object.
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, :through => :favorites</tt> will look for a
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, :dependent => :destroy # destroys the associated credit card
1303
- # has_one :credit_card, :dependent => :nullify # updates the associated records foreign
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, :class_name => "Comment", :order => "posted_on"
1306
- # has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"
1307
- # has_one :attachment, :as => :attachable
1308
- # has_one :boss, :readonly => :true
1309
- # has_one :club, :through => :membership
1310
- # has_one :primary_address, :through => :addressables, :conditions => ["addressable.primary = ?", true], :source => :addressable
1311
- def has_one(name, options = {})
1312
- Builder::HasOne.build(self, name, options)
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, :class_name => "Person"</tt> will use a foreign key
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, :polymorphic => true</tt>
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). You can also specify a custom counter
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>:counter_cache => :my_custom_counter</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 now)
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, :foreign_key => "client_of"
1421
- # belongs_to :person, :primary_key => "name", :foreign_key => "person_name"
1422
- # belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
1423
- # belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
1424
- # :conditions => 'discounts > #{payments_count}'
1425
- # belongs_to :attachable, :polymorphic => true
1426
- # belongs_to :project, :readonly => true
1427
- # belongs_to :post, :counter_cache => true
1428
- # belongs_to :company, :touch => true
1429
- # belongs_to :company, :touch => :employees_last_updated_at
1430
- def belongs_to(name, options = {})
1431
- Builder::BelongsTo.build(self, name, options)
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" outranks "P".
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, :id => false do |t|
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 sql without waiting for the save or update call on the
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, :include => [ :milestones, :manager ]
1597
- # has_and_belongs_to_many :nations, :class_name => "Country"
1598
- # has_and_belongs_to_many :categories, :join_table => "prods_cats"
1599
- # has_and_belongs_to_many :categories, :readonly => true
1600
- # has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
1601
- # "DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}"
1602
- def has_and_belongs_to_many(name, options = {}, &extension)
1603
- Builder::HasAndBelongsToMany.build(self, name, options, &extension)
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