activerecord 3.2.22.4 → 4.0.13

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2799 -617
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +23 -32
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +40 -34
  7. data/lib/active_record/association_relation.rb +22 -0
  8. data/lib/active_record/associations/alias_tracker.rb +4 -2
  9. data/lib/active_record/associations/association.rb +60 -46
  10. data/lib/active_record/associations/association_scope.rb +46 -40
  11. data/lib/active_record/associations/belongs_to_association.rb +17 -4
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  13. data/lib/active_record/associations/builder/association.rb +81 -28
  14. data/lib/active_record/associations/builder/belongs_to.rb +73 -56
  15. data/lib/active_record/associations/builder/collection_association.rb +54 -40
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -64
  18. data/lib/active_record/associations/builder/has_one.rb +13 -50
  19. data/lib/active_record/associations/builder/singular_association.rb +13 -13
  20. data/lib/active_record/associations/collection_association.rb +130 -96
  21. data/lib/active_record/associations/collection_proxy.rb +916 -63
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +15 -13
  23. data/lib/active_record/associations/has_many_association.rb +35 -8
  24. data/lib/active_record/associations/has_many_through_association.rb +37 -17
  25. data/lib/active_record/associations/has_one_association.rb +42 -19
  26. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_association.rb +39 -22
  28. data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
  29. data/lib/active_record/associations/join_dependency/join_part.rb +21 -8
  30. data/lib/active_record/associations/join_dependency.rb +30 -9
  31. data/lib/active_record/associations/join_helper.rb +1 -11
  32. data/lib/active_record/associations/preloader/association.rb +29 -33
  33. data/lib/active_record/associations/preloader/collection_association.rb +1 -1
  34. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +2 -2
  35. data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
  36. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  37. data/lib/active_record/associations/preloader/through_association.rb +13 -17
  38. data/lib/active_record/associations/preloader.rb +20 -43
  39. data/lib/active_record/associations/singular_association.rb +11 -11
  40. data/lib/active_record/associations/through_association.rb +3 -3
  41. data/lib/active_record/associations.rb +223 -282
  42. data/lib/active_record/attribute_assignment.rb +134 -154
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
  44. data/lib/active_record/attribute_methods/dirty.rb +36 -29
  45. data/lib/active_record/attribute_methods/primary_key.rb +45 -31
  46. data/lib/active_record/attribute_methods/query.rb +5 -4
  47. data/lib/active_record/attribute_methods/read.rb +67 -90
  48. data/lib/active_record/attribute_methods/serialization.rb +133 -70
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +51 -45
  50. data/lib/active_record/attribute_methods/write.rb +34 -39
  51. data/lib/active_record/attribute_methods.rb +268 -108
  52. data/lib/active_record/autosave_association.rb +80 -73
  53. data/lib/active_record/base.rb +54 -451
  54. data/lib/active_record/callbacks.rb +60 -22
  55. data/lib/active_record/coders/yaml_column.rb +18 -21
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +347 -197
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +146 -138
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -19
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +19 -3
  61. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +151 -142
  62. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +499 -217
  64. data/lib/active_record/connection_adapters/abstract/transaction.rb +208 -0
  65. data/lib/active_record/connection_adapters/abstract_adapter.rb +209 -44
  66. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +169 -61
  67. data/lib/active_record/connection_adapters/column.rb +67 -36
  68. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +28 -29
  70. data/lib/active_record/connection_adapters/mysql_adapter.rb +200 -73
  71. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +98 -0
  72. data/lib/active_record/connection_adapters/postgresql/cast.rb +160 -0
  73. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +240 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +374 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +183 -0
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +508 -0
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +544 -899
  79. data/lib/active_record/connection_adapters/schema_cache.rb +76 -16
  80. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +595 -16
  81. data/lib/active_record/connection_handling.rb +98 -0
  82. data/lib/active_record/core.rb +472 -0
  83. data/lib/active_record/counter_cache.rb +107 -108
  84. data/lib/active_record/dynamic_matchers.rb +115 -63
  85. data/lib/active_record/errors.rb +36 -18
  86. data/lib/active_record/explain.rb +15 -63
  87. data/lib/active_record/explain_registry.rb +30 -0
  88. data/lib/active_record/explain_subscriber.rb +8 -4
  89. data/lib/active_record/fixture_set/file.rb +55 -0
  90. data/lib/active_record/fixtures.rb +159 -155
  91. data/lib/active_record/inheritance.rb +93 -59
  92. data/lib/active_record/integration.rb +8 -8
  93. data/lib/active_record/locale/en.yml +8 -1
  94. data/lib/active_record/locking/optimistic.rb +39 -43
  95. data/lib/active_record/locking/pessimistic.rb +4 -4
  96. data/lib/active_record/log_subscriber.rb +19 -9
  97. data/lib/active_record/migration/command_recorder.rb +102 -33
  98. data/lib/active_record/migration/join_table.rb +15 -0
  99. data/lib/active_record/migration.rb +411 -173
  100. data/lib/active_record/model_schema.rb +81 -94
  101. data/lib/active_record/nested_attributes.rb +173 -131
  102. data/lib/active_record/null_relation.rb +67 -0
  103. data/lib/active_record/persistence.rb +254 -106
  104. data/lib/active_record/query_cache.rb +18 -36
  105. data/lib/active_record/querying.rb +19 -15
  106. data/lib/active_record/railtie.rb +113 -38
  107. data/lib/active_record/railties/console_sandbox.rb +3 -4
  108. data/lib/active_record/railties/controller_runtime.rb +4 -3
  109. data/lib/active_record/railties/databases.rake +115 -368
  110. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  111. data/lib/active_record/readonly_attributes.rb +7 -3
  112. data/lib/active_record/reflection.rb +110 -61
  113. data/lib/active_record/relation/batches.rb +29 -29
  114. data/lib/active_record/relation/calculations.rb +155 -125
  115. data/lib/active_record/relation/delegation.rb +94 -18
  116. data/lib/active_record/relation/finder_methods.rb +151 -203
  117. data/lib/active_record/relation/merger.rb +188 -0
  118. data/lib/active_record/relation/predicate_builder.rb +85 -42
  119. data/lib/active_record/relation/query_methods.rb +793 -146
  120. data/lib/active_record/relation/spawn_methods.rb +43 -150
  121. data/lib/active_record/relation.rb +293 -173
  122. data/lib/active_record/result.rb +48 -7
  123. data/lib/active_record/runtime_registry.rb +17 -0
  124. data/lib/active_record/sanitization.rb +41 -54
  125. data/lib/active_record/schema.rb +19 -12
  126. data/lib/active_record/schema_dumper.rb +41 -41
  127. data/lib/active_record/schema_migration.rb +46 -0
  128. data/lib/active_record/scoping/default.rb +56 -52
  129. data/lib/active_record/scoping/named.rb +78 -103
  130. data/lib/active_record/scoping.rb +54 -124
  131. data/lib/active_record/serialization.rb +6 -2
  132. data/lib/active_record/serializers/xml_serializer.rb +9 -15
  133. data/lib/active_record/statement_cache.rb +26 -0
  134. data/lib/active_record/store.rb +131 -15
  135. data/lib/active_record/tasks/database_tasks.rb +204 -0
  136. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  137. data/lib/active_record/tasks/mysql_database_tasks.rb +144 -0
  138. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  140. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  141. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  142. data/lib/active_record/test_case.rb +67 -38
  143. data/lib/active_record/timestamp.rb +16 -11
  144. data/lib/active_record/transactions.rb +73 -51
  145. data/lib/active_record/validations/associated.rb +19 -13
  146. data/lib/active_record/validations/presence.rb +65 -0
  147. data/lib/active_record/validations/uniqueness.rb +110 -57
  148. data/lib/active_record/validations.rb +18 -17
  149. data/lib/active_record/version.rb +7 -6
  150. data/lib/active_record.rb +63 -45
  151. data/lib/rails/generators/active_record/migration/migration_generator.rb +45 -8
  152. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
  153. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  154. data/lib/rails/generators/active_record/model/model_generator.rb +5 -4
  155. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  156. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  157. data/lib/rails/generators/active_record.rb +3 -5
  158. metadata +43 -29
  159. data/examples/associations.png +0 -0
  160. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  161. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  162. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  163. data/lib/active_record/dynamic_finder_match.rb +0 -68
  164. data/lib/active_record/dynamic_scope_match.rb +0 -23
  165. data/lib/active_record/fixtures/file.rb +0 -65
  166. data/lib/active_record/identity_map.rb +0 -162
  167. data/lib/active_record/observer.rb +0 -121
  168. data/lib/active_record/session_store.rb +0 -360
  169. data/lib/rails/generators/active_record/migration.rb +0 -15
  170. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  171. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  172. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  173. 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
 
@@ -156,7 +159,7 @@ module ActiveRecord
156
159
  association = association_instance_get(name)
157
160
 
158
161
  if association.nil?
159
- reflection = self.class.reflect_on_association(name)
162
+ raise AssociationNotFoundError.new(self, name) unless reflection = self.class.reflect_on_association(name)
160
163
  association = reflection.association_class.new(self, reflection)
161
164
  association_instance_set(name, association)
162
165
  end
@@ -194,30 +197,10 @@ module ActiveRecord
194
197
  # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
195
198
  # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
196
199
  # * <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>
200
+ # <tt>Project#milestones.delete(milestone), Project#milestones.destroy(milestone), Project#milestones.find(milestone_id),</tt>
198
201
  # <tt>Project#milestones.build, Project#milestones.create</tt>
199
202
  # * <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.
203
+ # <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
221
204
  #
222
205
  # === A word of warning
223
206
  #
@@ -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
@@ -401,14 +406,35 @@ 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
+ # == Association callbacks
405
431
  #
406
432
  # Similar to the normal callbacks that hook into the life cycle of an Active Record object,
407
433
  # you can also define callbacks that get triggered when you add an object to or remove an
408
434
  # object from an association collection.
409
435
  #
410
436
  # class Project
411
- # has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
437
+ # has_and_belongs_to_many :developers, after_add: :evaluate_velocity
412
438
  #
413
439
  # def evaluate_velocity(developer)
414
440
  # ...
@@ -419,7 +445,7 @@ module ActiveRecord
419
445
  #
420
446
  # class Project
421
447
  # has_and_belongs_to_many :developers,
422
- # :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
448
+ # after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
423
449
  # end
424
450
  #
425
451
  # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
@@ -428,7 +454,7 @@ module ActiveRecord
428
454
  # added to the collection. Same with the +before_remove+ callbacks; if an exception is
429
455
  # thrown the object doesn't get removed.
430
456
  #
431
- # === Association extensions
457
+ # == Association extensions
432
458
  #
433
459
  # The proxy objects that control the access to associations can be extended through anonymous
434
460
  # modules. This is especially beneficial for adding new finders, creators, and other
@@ -438,7 +464,7 @@ module ActiveRecord
438
464
  # has_many :people do
439
465
  # def find_or_create_by_name(name)
440
466
  # first_name, last_name = name.split(" ", 2)
441
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
467
+ # find_or_create_by(first_name: first_name, last_name: last_name)
442
468
  # end
443
469
  # end
444
470
  # end
@@ -453,25 +479,16 @@ module ActiveRecord
453
479
  # module FindOrCreateByNameExtension
454
480
  # def find_or_create_by_name(name)
455
481
  # first_name, last_name = name.split(" ", 2)
456
- # find_or_create_by_first_name_and_last_name(first_name, last_name)
482
+ # find_or_create_by(first_name: first_name, last_name: last_name)
457
483
  # end
458
484
  # end
459
485
  #
460
486
  # class Account < ActiveRecord::Base
461
- # has_many :people, :extend => FindOrCreateByNameExtension
487
+ # has_many :people, -> { extending FindOrCreateByNameExtension }
462
488
  # end
463
489
  #
464
490
  # 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]
491
+ # has_many :people, -> { extending FindOrCreateByNameExtension }
475
492
  # end
476
493
  #
477
494
  # Some extensions can only be made to work with knowledge of the association's internals.
@@ -489,7 +506,7 @@ module ActiveRecord
489
506
  # the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside
490
507
  # association extensions.
491
508
  #
492
- # === Association Join Models
509
+ # == Association Join Models
493
510
  #
494
511
  # Has Many associations can be configured with the <tt>:through</tt> option to use an
495
512
  # explicit join model to retrieve the data. This operates similarly to a
@@ -498,7 +515,7 @@ module ActiveRecord
498
515
  #
499
516
  # class Author < ActiveRecord::Base
500
517
  # has_many :authorships
501
- # has_many :books, :through => :authorships
518
+ # has_many :books, through: :authorships
502
519
  # end
503
520
  #
504
521
  # class Authorship < ActiveRecord::Base
@@ -514,7 +531,7 @@ module ActiveRecord
514
531
  #
515
532
  # class Firm < ActiveRecord::Base
516
533
  # has_many :clients
517
- # has_many :invoices, :through => :clients
534
+ # has_many :invoices, through: :clients
518
535
  # end
519
536
  #
520
537
  # class Client < ActiveRecord::Base
@@ -534,7 +551,7 @@ module ActiveRecord
534
551
  #
535
552
  # class Group < ActiveRecord::Base
536
553
  # has_many :users
537
- # has_many :avatars, :through => :users
554
+ # has_many :avatars, through: :users
538
555
  # end
539
556
  #
540
557
  # class User < ActiveRecord::Base
@@ -547,7 +564,7 @@ module ActiveRecord
547
564
  # end
548
565
  #
549
566
  # @group = Group.first
550
- # @group.users.collect { |u| u.avatar }.flatten # select all avatars for all users in the group
567
+ # @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
551
568
  # @group.avatars # selects all avatars by going through the User join model.
552
569
  #
553
570
  # An important caveat with going through +has_one+ or +has_many+ associations on the
@@ -562,7 +579,7 @@ module ActiveRecord
562
579
  # works correctly (where <tt>tags</tt> is a +has_many+ <tt>:through</tt> association):
563
580
  #
564
581
  # @post = Post.first
565
- # @tag = @post.tags.build :name => "ruby"
582
+ # @tag = @post.tags.build name: "ruby"
566
583
  # @tag.save
567
584
  #
568
585
  # The last line ought to save the through record (a <tt>Taggable</tt>). This will only work if the
@@ -570,18 +587,18 @@ module ActiveRecord
570
587
  #
571
588
  # class Taggable < ActiveRecord::Base
572
589
  # belongs_to :post
573
- # belongs_to :tag, :inverse_of => :taggings
590
+ # belongs_to :tag, inverse_of: :taggings
574
591
  # end
575
592
  #
576
- # === Nested Associations
593
+ # == Nested Associations
577
594
  #
578
595
  # You can actually specify *any* association with the <tt>:through</tt> option, including an
579
596
  # association which has a <tt>:through</tt> option itself. For example:
580
597
  #
581
598
  # class Author < ActiveRecord::Base
582
599
  # has_many :posts
583
- # has_many :comments, :through => :posts
584
- # has_many :commenters, :through => :comments
600
+ # has_many :comments, through: :posts
601
+ # has_many :commenters, through: :comments
585
602
  # end
586
603
  #
587
604
  # class Post < ActiveRecord::Base
@@ -599,12 +616,12 @@ module ActiveRecord
599
616
  #
600
617
  # class Author < ActiveRecord::Base
601
618
  # has_many :posts
602
- # has_many :commenters, :through => :posts
619
+ # has_many :commenters, through: :posts
603
620
  # end
604
621
  #
605
622
  # class Post < ActiveRecord::Base
606
623
  # has_many :comments
607
- # has_many :commenters, :through => :comments
624
+ # has_many :commenters, through: :comments
608
625
  # end
609
626
  #
610
627
  # class Comment < ActiveRecord::Base
@@ -616,18 +633,18 @@ module ActiveRecord
616
633
  # add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
617
634
  # intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
618
635
  #
619
- # === Polymorphic Associations
636
+ # == Polymorphic Associations
620
637
  #
621
638
  # Polymorphic associations on models are not restricted on what types of models they
622
639
  # can be associated with. Rather, they specify an interface that a +has_many+ association
623
640
  # must adhere to.
624
641
  #
625
642
  # class Asset < ActiveRecord::Base
626
- # belongs_to :attachable, :polymorphic => true
643
+ # belongs_to :attachable, polymorphic: true
627
644
  # end
628
645
  #
629
646
  # class Post < ActiveRecord::Base
630
- # has_many :assets, :as => :attachable # The :as option specifies the polymorphic interface to use.
647
+ # has_many :assets, as: :attachable # The :as option specifies the polymorphic interface to use.
631
648
  # end
632
649
  #
633
650
  # @asset.attachable = @post
@@ -644,16 +661,16 @@ module ActiveRecord
644
661
  # column in the posts table.
645
662
  #
646
663
  # class Asset < ActiveRecord::Base
647
- # belongs_to :attachable, :polymorphic => true
664
+ # belongs_to :attachable, polymorphic: true
648
665
  #
649
- # def attachable_type=(sType)
650
- # super(sType.to_s.classify.constantize.base_class.to_s)
666
+ # def attachable_type=(klass)
667
+ # super(klass.to_s.classify.constantize.base_class.to_s)
651
668
  # end
652
669
  # end
653
670
  #
654
671
  # 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
672
+ # # because we store "Post" in attachable_type now dependent: :destroy will work
673
+ # has_many :assets, as: :attachable, dependent: :destroy
657
674
  # end
658
675
  #
659
676
  # class GuestPost < Post
@@ -715,7 +732,7 @@ module ActiveRecord
715
732
  #
716
733
  # To include a deep hierarchy of associations, use a hash:
717
734
  #
718
- # Post.includes(:author, {:comments => {:author => :gravatar}}).each do |post|
735
+ # Post.includes(:author, {comments: {author: :gravatar}}).each do |post|
719
736
  #
720
737
  # That'll grab not only all the comments but all their authors and gravatar pictures.
721
738
  # You can mix and match symbols, arrays and hashes in any combination to describe the
@@ -731,7 +748,7 @@ module ActiveRecord
731
748
  # other than the main one. If this is the case Active Record falls back to the previously
732
749
  # used LEFT OUTER JOIN based strategy. For example
733
750
  #
734
- # Post.includes([:author, :comments]).where(['comments.approved = ?', true]).all
751
+ # Post.includes([:author, :comments]).where(['comments.approved = ?', true])
735
752
  #
736
753
  # This will result in a single SQL query with joins along the lines of:
737
754
  # <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
@@ -740,13 +757,13 @@ module ActiveRecord
740
757
  # In the above example posts with no approved comments are not returned at all, because
741
758
  # the conditions apply to the SQL statement as a whole and not just to the association.
742
759
  # 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.
760
+ # <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
744
761
  #
745
762
  # If you do want eager load only some members of an association it is usually more natural
746
763
  # to include an association which has conditions defined on it:
747
764
  #
748
765
  # class Post < ActiveRecord::Base
749
- # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true]
766
+ # has_many :approved_comments, -> { where approved: true }, class_name: 'Comment'
750
767
  # end
751
768
  #
752
769
  # Post.includes(:approved_comments)
@@ -758,18 +775,15 @@ module ActiveRecord
758
775
  # returning all the associated objects:
759
776
  #
760
777
  # class Picture < ActiveRecord::Base
761
- # has_many :most_recent_comments, :class_name => 'Comment', :order => 'id DESC', :limit => 10
778
+ # has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment'
762
779
  # end
763
780
  #
764
781
  # Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
765
782
  #
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
783
  # Eager loading is supported with polymorphic associations.
770
784
  #
771
785
  # class Address < ActiveRecord::Base
772
- # belongs_to :addressable, :polymorphic => true
786
+ # belongs_to :addressable, polymorphic: true
773
787
  # end
774
788
  #
775
789
  # A call that tries to eager load the addressable model
@@ -803,10 +817,10 @@ module ActiveRecord
803
817
  #
804
818
  # TreeMixin.joins(:children)
805
819
  # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
806
- # TreeMixin.joins(:children => :parent)
820
+ # TreeMixin.joins(children: :parent)
807
821
  # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
808
822
  # INNER JOIN parents_mixins ...
809
- # TreeMixin.joins(:children => {:parent => :children})
823
+ # TreeMixin.joins(children: {parent: :children})
810
824
  # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
811
825
  # INNER JOIN parents_mixins ...
812
826
  # INNER JOIN mixins childrens_mixins_2
@@ -815,10 +829,10 @@ module ActiveRecord
815
829
  #
816
830
  # Post.joins(:categories)
817
831
  # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
818
- # Post.joins(:categories => :posts)
832
+ # Post.joins(categories: :posts)
819
833
  # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
820
834
  # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
821
- # Post.joins(:categories => {:posts => :categories})
835
+ # Post.joins(categories: {posts: :categories})
822
836
  # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
823
837
  # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
824
838
  # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
@@ -843,8 +857,8 @@ module ActiveRecord
843
857
  # module MyApplication
844
858
  # module Business
845
859
  # class Firm < ActiveRecord::Base
846
- # has_many :clients
847
- # end
860
+ # has_many :clients
861
+ # end
848
862
  #
849
863
  # class Client < ActiveRecord::Base; end
850
864
  # end
@@ -862,7 +876,7 @@ module ActiveRecord
862
876
  #
863
877
  # module Billing
864
878
  # class Account < ActiveRecord::Base
865
- # belongs_to :firm, :class_name => "MyApplication::Business::Firm"
879
+ # belongs_to :firm, class_name: "MyApplication::Business::Firm"
866
880
  # end
867
881
  # end
868
882
  # end
@@ -904,16 +918,16 @@ module ActiveRecord
904
918
  # example, if we changed our model definitions to:
905
919
  #
906
920
  # class Dungeon < ActiveRecord::Base
907
- # has_many :traps, :inverse_of => :dungeon
908
- # has_one :evil_wizard, :inverse_of => :dungeon
921
+ # has_many :traps, inverse_of: :dungeon
922
+ # has_one :evil_wizard, inverse_of: :dungeon
909
923
  # end
910
924
  #
911
925
  # class Trap < ActiveRecord::Base
912
- # belongs_to :dungeon, :inverse_of => :traps
926
+ # belongs_to :dungeon, inverse_of: :traps
913
927
  # end
914
928
  #
915
929
  # class EvilWizard < ActiveRecord::Base
916
- # belongs_to :dungeon, :inverse_of => :evil_wizard
930
+ # belongs_to :dungeon, inverse_of: :evil_wizard
917
931
  # end
918
932
  #
919
933
  # Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same
@@ -936,13 +950,19 @@ module ActiveRecord
936
950
  # For example:
937
951
  #
938
952
  # class Author
939
- # has_many :posts, :dependent => :destroy
953
+ # has_many :posts, dependent: :destroy
940
954
  # end
941
955
  # Author.find(1).destroy # => Will destroy all of the author's posts, too
942
956
  #
943
957
  # The <tt>:dependent</tt> option can have different values which specify how the deletion
944
958
  # is done. For more information, see the documentation for this option on the different
945
- # specific association types.
959
+ # specific association types. When no option is given, the behavior is to do nothing
960
+ # with the associated records when destroying a record.
961
+ #
962
+ # Note that <tt>:dependent</tt> is implemented using Rails' callback
963
+ # system, which works by processing callbacks in order. Therefore, other
964
+ # callbacks declared either before or after the <tt>:dependent</tt> option
965
+ # can affect what it does.
946
966
  #
947
967
  # === Delete or destroy?
948
968
  #
@@ -952,8 +972,8 @@ module ActiveRecord
952
972
  # For +has_and_belongs_to_many+, <tt>delete</tt> and <tt>destroy</tt> are the same: they
953
973
  # cause the records in the join table to be removed.
954
974
  #
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
975
+ # For +has_many+, <tt>destroy</tt> and <tt>destroy_all</tt> will always call the <tt>destroy</tt> method of the
976
+ # record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either
957
977
  # do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
958
978
  # if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
959
979
  # The default strategy is <tt>:nullify</tt> (set the foreign keys to <tt>nil</tt>), except for
@@ -974,7 +994,7 @@ module ActiveRecord
974
994
  # associated objects themselves. So with +has_and_belongs_to_many+ and +has_many+
975
995
  # <tt>:through</tt>, the join records will be deleted, but the associated records won't.
976
996
  #
977
- # This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.find_by_name('food'))</tt>
997
+ # This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.find_by(name: 'food'))</tt>
978
998
  # you would want the 'food' tag to be unlinked from the post, rather than for the tag itself
979
999
  # to be removed from the database.
980
1000
  #
@@ -1011,15 +1031,21 @@ module ActiveRecord
1011
1031
  # [collection<<(object, ...)]
1012
1032
  # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
1013
1033
  # Note that this operation instantly fires update sql without waiting for the save or update call on the
1014
- # parent object.
1034
+ # parent object, unless the parent object is a new record.
1015
1035
  # [collection.delete(object, ...)]
1016
1036
  # 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>.
1037
+ # Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>,
1038
+ # and deleted if they're associated with <tt>dependent: :delete_all</tt>.
1019
1039
  #
1020
1040
  # 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.
1041
+ # nullified) by default, but you can specify <tt>dependent: :destroy</tt> or
1042
+ # <tt>dependent: :nullify</tt> to override this.
1043
+ # [collection.destroy(object, ...)]
1044
+ # Removes one or more objects from the collection by running <tt>destroy</tt> on
1045
+ # each record, regardless of any dependent option, ensuring callbacks are run.
1046
+ #
1047
+ # If the <tt>:through</tt> option is used, then the join records are destroyed
1048
+ # instead, not the objects themselves.
1023
1049
  # [collection=objects]
1024
1050
  # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
1025
1051
  # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
@@ -1031,8 +1057,8 @@ module ActiveRecord
1031
1057
  # method loads the models and calls <tt>collection=</tt>. See above.
1032
1058
  # [collection.clear]
1033
1059
  # 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+.
1060
+ # are associated with <tt>dependent: :destroy</tt>, deletes them directly from the
1061
+ # database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
1036
1062
  # If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
1037
1063
  # Join models are directly deleted.
1038
1064
  # [collection.empty?]
@@ -1053,6 +1079,9 @@ module ActiveRecord
1053
1079
  # with +attributes+, linked to this object through a foreign key, and that has already
1054
1080
  # been saved (if it passed the validation). *Note*: This only works if the base model
1055
1081
  # already exists in the DB, not if it is a new (unsaved) record!
1082
+ # [collection.create!(attributes = {})]
1083
+ # Does the same as <tt>collection.create</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
1084
+ # if the record is invalid.
1056
1085
  #
1057
1086
  # (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
1058
1087
  # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
@@ -1060,19 +1089,21 @@ module ActiveRecord
1060
1089
  # === Example
1061
1090
  #
1062
1091
  # 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>)
1092
+ # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
1064
1093
  # * <tt>Firm#clients<<</tt>
1065
1094
  # * <tt>Firm#clients.delete</tt>
1095
+ # * <tt>Firm#clients.destroy</tt>
1066
1096
  # * <tt>Firm#clients=</tt>
1067
1097
  # * <tt>Firm#client_ids</tt>
1068
1098
  # * <tt>Firm#client_ids=</tt>
1069
1099
  # * <tt>Firm#clients.clear</tt>
1070
1100
  # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
1071
1101
  # * <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>)
1102
+ # * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
1103
+ # * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
1074
1104
  # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
1075
1105
  # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
1106
+ # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
1076
1107
  # The declaration can also include an options hash to specialize the behavior of the association.
1077
1108
  #
1078
1109
  # === Options
@@ -1081,15 +1112,6 @@ module ActiveRecord
1081
1112
  # from the association name. So <tt>has_many :products</tt> will by default be linked
1082
1113
  # to the Product class, but if the real class name is SpecialProduct, you'll have to
1083
1114
  # 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
1115
  # [:foreign_key]
1094
1116
  # Specify the foreign key used for the association. By default this is guessed to be the name
1095
1117
  # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+
@@ -1097,44 +1119,24 @@ module ActiveRecord
1097
1119
  # [:primary_key]
1098
1120
  # Specify the method that returns the primary key used for the association. By default this is +id+.
1099
1121
  # [: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.
1122
+ # Controls what happens to the associated objects when
1123
+ # their owner is destroyed. Note that these are implemented as
1124
+ # callbacks, and Rails executes callbacks in order. Therefore, other
1125
+ # similar callbacks may affect the :dependent behavior, and the
1126
+ # :dependent behavior may affect other callbacks.
1127
+ #
1128
+ # * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
1129
+ # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
1130
+ # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
1131
+ # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records.
1132
+ # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
1106
1133
  #
1107
1134
  # If using with the <tt>:through</tt> option, the association on the join model must be
1108
1135
  # a +belongs_to+, and the records which get deleted are the join records, rather than
1109
1136
  # 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.
1137
+ # [:counter_cache]
1138
+ # This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
1139
+ # when you customized the name of your <tt>:counter_cache</tt> on the <tt>belongs_to</tt> association.
1138
1140
  # [:as]
1139
1141
  # Specifies a polymorphic interface (See <tt>belongs_to</tt>).
1140
1142
  # [:through]
@@ -1156,21 +1158,21 @@ module ActiveRecord
1156
1158
  # [:source]
1157
1159
  # Specifies the source association name used by <tt>has_many :through</tt> queries.
1158
1160
  # 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
1161
+ # <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
1160
1162
  # <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
1161
1163
  # [:source_type]
1162
1164
  # Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
1163
1165
  # 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
1166
  # [:validate]
1169
1167
  # If +false+, don't validate the associated objects when saving the parent object. true by default.
1170
1168
  # [:autosave]
1171
1169
  # If true, always save the associated objects or destroy them if marked for destruction,
1172
1170
  # 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.
1171
+ # By default, only save associated objects that are new records. This option is implemented as a
1172
+ # before_save callback. Because callbacks are run in the order they are defined, associated objects
1173
+ # may need to be explicitly saved in any user-defined before_save callbacks.
1174
+ #
1175
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
1174
1176
  # [:inverse_of]
1175
1177
  # Specifies the name of the <tt>belongs_to</tt> association on the associated object
1176
1178
  # that is the inverse of this <tt>has_many</tt> association. Does not work in combination
@@ -1178,24 +1180,16 @@ module ActiveRecord
1178
1180
  # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1179
1181
  #
1180
1182
  # 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)
1183
+ # has_many :comments, -> { order "posted_on" }
1184
+ # has_many :comments, -> { includes :author }
1185
+ # has_many :people, -> { where("deleted = 0").order("name") }, class_name: "Person"
1186
+ # has_many :tracks, -> { order "position" }, dependent: :destroy
1187
+ # has_many :comments, dependent: :nullify
1188
+ # has_many :tags, as: :taggable
1189
+ # has_many :reports, -> { readonly }
1190
+ # has_many :subscribers, through: :subscriptions, source: :user
1191
+ def has_many(name, scope = nil, options = {}, &extension)
1192
+ Builder::HasMany.build(self, name, scope, options, &extension)
1199
1193
  end
1200
1194
 
1201
1195
  # Specifies a one-to-one association with another class. This method should only be used
@@ -1228,7 +1222,7 @@ module ActiveRecord
1228
1222
  # === Example
1229
1223
  #
1230
1224
  # 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>)
1225
+ # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
1232
1226
  # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
1233
1227
  # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
1234
1228
  # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
@@ -1243,34 +1237,23 @@ module ActiveRecord
1243
1237
  # Specify the class name of the association. Use it only if that name can't be inferred
1244
1238
  # from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
1245
1239
  # 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
1240
  # [: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.
1241
+ # Controls what happens to the associated object when
1242
+ # its owner is destroyed:
1243
+ #
1244
+ # * <tt>:destroy</tt> causes the associated object to also be destroyed
1245
+ # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
1246
+ # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
1247
+ # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record
1248
+ # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
1260
1249
  # [:foreign_key]
1261
1250
  # Specify the foreign key used for the association. By default this is guessed to be the name
1262
1251
  # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association
1263
1252
  # will use "person_id" as the default <tt>:foreign_key</tt>.
1264
1253
  # [:primary_key]
1265
1254
  # 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
1255
  # [:as]
1269
1256
  # 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
1257
  # [:through]
1275
1258
  # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
1276
1259
  # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
@@ -1279,19 +1262,19 @@ module ActiveRecord
1279
1262
  # [:source]
1280
1263
  # Specifies the source association name used by <tt>has_one :through</tt> queries.
1281
1264
  # Only use it if the name cannot be inferred from the association.
1282
- # <tt>has_one :favorite, :through => :favorites</tt> will look for a
1265
+ # <tt>has_one :favorite, through: :favorites</tt> will look for a
1283
1266
  # <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
1284
1267
  # [:source_type]
1285
1268
  # Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
1286
1269
  # association is a polymorphic +belongs_to+.
1287
- # [:readonly]
1288
- # If true, the associated object is readonly through the association.
1289
1270
  # [:validate]
1290
1271
  # If +false+, don't validate the associated object when saving the parent object. +false+ by default.
1291
1272
  # [:autosave]
1292
1273
  # If true, always save the associated object or destroy it if marked for destruction,
1293
1274
  # when saving the parent object. If false, never save or destroy the associated object.
1294
1275
  # By default, only save the associated object if it's a new record.
1276
+ #
1277
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
1295
1278
  # [:inverse_of]
1296
1279
  # Specifies the name of the <tt>belongs_to</tt> association on the associated object
1297
1280
  # that is the inverse of this <tt>has_one</tt> association. Does not work in combination
@@ -1299,17 +1282,17 @@ module ActiveRecord
1299
1282
  # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1300
1283
  #
1301
1284
  # 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
1285
+ # has_one :credit_card, dependent: :destroy # destroys the associated credit card
1286
+ # has_one :credit_card, dependent: :nullify # updates the associated records foreign
1304
1287
  # # 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)
1288
+ # has_one :last_comment, -> { order 'posted_on' }, class_name: "Comment"
1289
+ # has_one :project_manager, -> { where role: 'project_manager' }, class_name: "Person"
1290
+ # has_one :attachment, as: :attachable
1291
+ # has_one :boss, readonly: :true
1292
+ # has_one :club, through: :membership
1293
+ # has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
1294
+ def has_one(name, scope = nil, options = {})
1295
+ Builder::HasOne.build(self, name, scope, options)
1313
1296
  end
1314
1297
 
1315
1298
  # Specifies a one-to-one association with another class. This method should only be used
@@ -1354,23 +1337,16 @@ module ActiveRecord
1354
1337
  # Specify the class name of the association. Use it only if that name can't be inferred
1355
1338
  # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
1356
1339
  # 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
1340
  # [:foreign_key]
1365
1341
  # Specify the foreign key used for the association. By default this is guessed to be the name
1366
1342
  # of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
1367
1343
  # 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
1344
+ # <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key
1369
1345
  # of "favorite_person_id".
1370
1346
  # [:foreign_type]
1371
1347
  # Specify the column used to store the associated object's type, if this is a polymorphic
1372
1348
  # 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>
1349
+ # suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt>
1374
1350
  # association will use "taggable_type" as the default <tt>:foreign_type</tt>.
1375
1351
  # [:primary_key]
1376
1352
  # Specify the method that returns the primary key of associated object used for the association.
@@ -1386,19 +1362,17 @@ module ActiveRecord
1386
1362
  # and +decrement_counter+. The counter cache is incremented when an object of this
1387
1363
  # class is created and decremented when it's destroyed. This requires that a column
1388
1364
  # 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
1365
+ # is used on the associate class (such as a Post class) - that is the migration for
1366
+ # <tt>#{table_name}_count</tt> is created on the associate class (such that Post.comments_count will
1367
+ # return the count cached, see note below). You can also specify a custom counter
1390
1368
  # 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>.)
1369
+ # option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
1392
1370
  # Note: Specifying a counter cache will add it to that model's list of readonly attributes
1393
1371
  # using +attr_readonly+.
1394
- # [:include]
1395
- # Specify second-order associations that should be eager loaded when this object is loaded.
1396
1372
  # [:polymorphic]
1397
1373
  # Specify this association is a polymorphic association by passing +true+.
1398
1374
  # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
1399
1375
  # 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
1376
  # [:validate]
1403
1377
  # If +false+, don't validate the associated objects when saving the parent object. +false+ by default.
1404
1378
  # [:autosave]
@@ -1406,6 +1380,8 @@ module ActiveRecord
1406
1380
  # saving the parent object.
1407
1381
  # If false, never save or destroy the associated object.
1408
1382
  # By default, only save the associated object if it's a new record.
1383
+ #
1384
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
1409
1385
  # [:touch]
1410
1386
  # If true, the associated object will be touched (the updated_at/on attributes set to now)
1411
1387
  # when this record is either saved or destroyed. If you specify a symbol, that attribute
@@ -1417,24 +1393,24 @@ module ActiveRecord
1417
1393
  # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1418
1394
  #
1419
1395
  # 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)
1396
+ # belongs_to :firm, foreign_key: "client_of"
1397
+ # belongs_to :person, primary_key: "name", foreign_key: "person_name"
1398
+ # belongs_to :author, class_name: "Person", foreign_key: "author_id"
1399
+ # belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count },
1400
+ # class_name: "Coupon", foreign_key: "coupon_id"
1401
+ # belongs_to :attachable, polymorphic: true
1402
+ # belongs_to :project, readonly: true
1403
+ # belongs_to :post, counter_cache: true
1404
+ # belongs_to :company, touch: true
1405
+ # belongs_to :company, touch: :employees_last_updated_at
1406
+ def belongs_to(name, scope = nil, options = {})
1407
+ Builder::BelongsTo.build(self, name, scope, options)
1432
1408
  end
1433
1409
 
1434
1410
  # Specifies a many-to-many relationship with another class. This associates two classes via an
1435
1411
  # intermediate join table. Unless the join table is explicitly specified as an option, it is
1436
1412
  # 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".
1413
+ # will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically.
1438
1414
  # Note that this precedence is calculated using the <tt><</tt> operator for String. This
1439
1415
  # means that if the strings are of different lengths, and the strings are equal when compared
1440
1416
  # up to the shortest length, then the longer string is considered of higher
@@ -1442,13 +1418,15 @@ module ActiveRecord
1442
1418
  # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
1443
1419
  # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
1444
1420
  # custom <tt>:join_table</tt> option if you need to.
1421
+ # If your tables share a common prefix, it will only appear once at the beginning. For example,
1422
+ # the tables "catalog_categories" and "catalog_products" generate a join table name of "catalog_categories_products".
1445
1423
  #
1446
1424
  # The join table should not have a primary key or a model associated with it. You must manually generate the
1447
1425
  # join table with a migration such as this:
1448
1426
  #
1449
1427
  # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
1450
1428
  # def change
1451
- # create_table :developers_projects, :id => false do |t|
1429
+ # create_table :developers_projects, id: false do |t|
1452
1430
  # t.integer :developer_id
1453
1431
  # t.integer :project_id
1454
1432
  # end
@@ -1468,10 +1446,13 @@ module ActiveRecord
1468
1446
  # Adds one or more objects to the collection by creating associations in the join table
1469
1447
  # (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
1470
1448
  # Note that this operation instantly fires update sql without waiting for the save or update call on the
1471
- # parent object.
1449
+ # parent object, unless the parent object is a new record.
1472
1450
  # [collection.delete(object, ...)]
1473
1451
  # Removes one or more objects from the collection by removing their associations from the join table.
1474
1452
  # This does not destroy the objects.
1453
+ # [collection.destroy(object, ...)]
1454
+ # Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
1455
+ # This does not destroy the objects.
1475
1456
  # [collection=objects]
1476
1457
  # Replaces the collection's content by deleting and adding objects as appropriate.
1477
1458
  # [collection_singular_ids]
@@ -1508,6 +1489,7 @@ module ActiveRecord
1508
1489
  # * <tt>Developer#projects</tt>
1509
1490
  # * <tt>Developer#projects<<</tt>
1510
1491
  # * <tt>Developer#projects.delete</tt>
1492
+ # * <tt>Developer#projects.destroy</tt>
1511
1493
  # * <tt>Developer#projects=</tt>
1512
1494
  # * <tt>Developer#project_ids</tt>
1513
1495
  # * <tt>Developer#project_ids=</tt>
@@ -1540,47 +1522,6 @@ module ActiveRecord
1540
1522
  # By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
1541
1523
  # So if a Person class makes a +has_and_belongs_to_many+ association to Project,
1542
1524
  # 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
1525
  # [:readonly]
1585
1526
  # If true, all the associated objects are readonly through the association.
1586
1527
  # [:validate]
@@ -1591,16 +1532,16 @@ module ActiveRecord
1591
1532
  # If false, never save or destroy the associated objects.
1592
1533
  # By default, only save associated objects that are new records.
1593
1534
  #
1535
+ # Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
1536
+ #
1594
1537
  # Option examples:
1595
1538
  # 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)
1539
+ # has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
1540
+ # has_and_belongs_to_many :nations, class_name: "Country"
1541
+ # has_and_belongs_to_many :categories, join_table: "prods_cats"
1542
+ # has_and_belongs_to_many :categories, -> { readonly }
1543
+ def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
1544
+ Builder::HasAndBelongsToMany.build(self, name, scope, options, &extension)
1604
1545
  end
1605
1546
  end
1606
1547
  end