duck_record 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1317 @@
1
+ require "active_support/core_ext/enumerable"
2
+ require "active_support/core_ext/string/conversions"
3
+ require "active_support/core_ext/module/remove_method"
4
+ require "duck_record/errors"
5
+
6
+ module DuckRecord
7
+ class AssociationNotFoundError < ConfigurationError #:nodoc:
8
+ def initialize(record = nil, association_name = nil)
9
+ if record && association_name
10
+ super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
11
+ else
12
+ super("Association was not found.")
13
+ end
14
+ end
15
+ end
16
+
17
+ # See ActiveRecord::Associations::ClassMethods for documentation.
18
+ module Associations # :nodoc:
19
+ extend ActiveSupport::Autoload
20
+ extend ActiveSupport::Concern
21
+
22
+ # These classes will be loaded when associations are created.
23
+ # So there is no need to eager load them.
24
+ autoload :Association
25
+ autoload :SingularAssociation
26
+ autoload :CollectionAssociation
27
+ autoload :ForeignAssociation
28
+ autoload :CollectionProxy
29
+
30
+ autoload :HasManyAssociation
31
+ autoload :HasOneAssociation
32
+
33
+ module Builder #:nodoc:
34
+ autoload :Association, "duck_record/associations/builder/association"
35
+ autoload :SingularAssociation, "duck_record/associations/builder/singular_association"
36
+ autoload :CollectionAssociation, "duck_record/associations/builder/collection_association"
37
+
38
+ autoload :HasOne, "duck_record/associations/builder/has_one"
39
+ autoload :HasMany, "duck_record/associations/builder/has_many"
40
+ end
41
+
42
+ def self.eager_load!
43
+ super
44
+ Preloader.eager_load!
45
+ end
46
+
47
+ # Returns the association instance for the given name, instantiating it if it doesn't already exist
48
+ def association(name) #:nodoc:
49
+ association = association_instance_get(name)
50
+
51
+ if association.nil?
52
+ unless reflection = self.class._reflect_on_association(name)
53
+ raise AssociationNotFoundError.new(self, name)
54
+ end
55
+ association = reflection.association_class.new(self, reflection)
56
+ association_instance_set(name, association)
57
+ end
58
+
59
+ association
60
+ end
61
+
62
+ def association_cached?(name) # :nodoc
63
+ @association_cache.key?(name)
64
+ end
65
+
66
+ def initialize_dup(*) # :nodoc:
67
+ @association_cache = {}
68
+ super
69
+ end
70
+
71
+ private
72
+ # Clears out the association cache.
73
+ def clear_association_cache
74
+ @association_cache.clear if persisted?
75
+ end
76
+
77
+ def init_internals
78
+ @association_cache = {}
79
+ super
80
+ end
81
+
82
+ # Returns the specified association instance if it exists, +nil+ otherwise.
83
+ def association_instance_get(name)
84
+ @association_cache[name]
85
+ end
86
+
87
+ # Set the specified association instance.
88
+ def association_instance_set(name, association)
89
+ @association_cache[name] = association
90
+ end
91
+
92
+ # \Associations are a set of macro-like class methods for tying objects together through
93
+ # foreign keys. They express relationships like "Project has one Project Manager"
94
+ # or "Project belongs to a Portfolio". Each macro adds a number of methods to the
95
+ # class which are specialized according to the collection or association symbol and the
96
+ # options hash. It works much the same way as Ruby's own <tt>attr*</tt>
97
+ # methods.
98
+ #
99
+ # class Project < ActiveRecord::Base
100
+ # belongs_to :portfolio
101
+ # has_one :project_manager
102
+ # has_many :milestones
103
+ # has_and_belongs_to_many :categories
104
+ # end
105
+ #
106
+ # The project class now has the following methods (and more) to ease the traversal and
107
+ # manipulation of its relationships:
108
+ # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
109
+ # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
110
+ # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
111
+ # <tt>Project#milestones.delete(milestone), Project#milestones.destroy(milestone), Project#milestones.find(milestone_id),</tt>
112
+ # <tt>Project#milestones.build, Project#milestones.create</tt>
113
+ # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
114
+ # <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
115
+ #
116
+ # === A word of warning
117
+ #
118
+ # Don't create associations that have the same name as {instance methods}[rdoc-ref:ActiveRecord::Core] of
119
+ # <tt>ActiveRecord::Base</tt>. Since the association adds a method with that name to
120
+ # its model, using an association with the same name as one provided by <tt>ActiveRecord::Base</tt> will override the method inherited through <tt>ActiveRecord::Base</tt> and will break things.
121
+ # For instance, +attributes+ and +connection+ would be bad choices for association names, because those names already exist in the list of <tt>ActiveRecord::Base</tt> instance methods.
122
+ #
123
+ # == Auto-generated methods
124
+ # See also Instance Public methods below for more details.
125
+ #
126
+ # === Singular associations (one-to-one)
127
+ # | | belongs_to |
128
+ # generated methods | belongs_to | :polymorphic | has_one
129
+ # ----------------------------------+------------+--------------+---------
130
+ # other(force_reload=false) | X | X | X
131
+ # other=(other) | X | X | X
132
+ # build_other(attributes={}) | X | | X
133
+ # create_other(attributes={}) | X | | X
134
+ # create_other!(attributes={}) | X | | X
135
+ #
136
+ # === Collection associations (one-to-many / many-to-many)
137
+ # | | | has_many
138
+ # generated methods | habtm | has_many | :through
139
+ # ----------------------------------+-------+----------+----------
140
+ # others(force_reload=false) | X | X | X
141
+ # others=(other,other,...) | X | X | X
142
+ # other_ids | X | X | X
143
+ # other_ids=(id,id,...) | X | X | X
144
+ # others<< | X | X | X
145
+ # others.push | X | X | X
146
+ # others.concat | X | X | X
147
+ # others.build(attributes={}) | X | X | X
148
+ # others.create(attributes={}) | X | X | X
149
+ # others.create!(attributes={}) | X | X | X
150
+ # others.size | X | X | X
151
+ # others.length | X | X | X
152
+ # others.count | X | X | X
153
+ # others.sum(*args) | X | X | X
154
+ # others.empty? | X | X | X
155
+ # others.clear | X | X | X
156
+ # others.delete(other,other,...) | X | X | X
157
+ # others.delete_all | X | X | X
158
+ # others.destroy(other,other,...) | X | X | X
159
+ # others.destroy_all | X | X | X
160
+ # others.find(*args) | X | X | X
161
+ # others.exists? | X | X | X
162
+ # others.distinct | X | X | X
163
+ # others.reset | X | X | X
164
+ #
165
+ # === Overriding generated methods
166
+ #
167
+ # Association methods are generated in a module included into the model
168
+ # class, making overrides easy. The original generated method can thus be
169
+ # called with +super+:
170
+ #
171
+ # class Car < ActiveRecord::Base
172
+ # belongs_to :owner
173
+ # belongs_to :old_owner
174
+ #
175
+ # def owner=(new_owner)
176
+ # self.old_owner = self.owner
177
+ # super
178
+ # end
179
+ # end
180
+ #
181
+ # The association methods module is included immediately after the
182
+ # generated attributes methods module, meaning an association will
183
+ # override the methods for an attribute with the same name.
184
+ #
185
+ # == Cardinality and associations
186
+ #
187
+ # Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
188
+ # relationships between models. Each model uses an association to describe its role in
189
+ # the relation. The #belongs_to association is always used in the model that has
190
+ # the foreign key.
191
+ #
192
+ # === One-to-one
193
+ #
194
+ # Use #has_one in the base, and #belongs_to in the associated model.
195
+ #
196
+ # class Employee < ActiveRecord::Base
197
+ # has_one :office
198
+ # end
199
+ # class Office < ActiveRecord::Base
200
+ # belongs_to :employee # foreign key - employee_id
201
+ # end
202
+ #
203
+ # === One-to-many
204
+ #
205
+ # Use #has_many in the base, and #belongs_to in the associated model.
206
+ #
207
+ # class Manager < ActiveRecord::Base
208
+ # has_many :employees
209
+ # end
210
+ # class Employee < ActiveRecord::Base
211
+ # belongs_to :manager # foreign key - manager_id
212
+ # end
213
+ #
214
+ # === Many-to-many
215
+ #
216
+ # There are two ways to build a many-to-many relationship.
217
+ #
218
+ # The first way uses a #has_many association with the <tt>:through</tt> option and a join model, so
219
+ # there are two stages of associations.
220
+ #
221
+ # class Assignment < ActiveRecord::Base
222
+ # belongs_to :programmer # foreign key - programmer_id
223
+ # belongs_to :project # foreign key - project_id
224
+ # end
225
+ # class Programmer < ActiveRecord::Base
226
+ # has_many :assignments
227
+ # has_many :projects, through: :assignments
228
+ # end
229
+ # class Project < ActiveRecord::Base
230
+ # has_many :assignments
231
+ # has_many :programmers, through: :assignments
232
+ # end
233
+ #
234
+ # For the second way, use #has_and_belongs_to_many in both models. This requires a join table
235
+ # that has no corresponding model or primary key.
236
+ #
237
+ # class Programmer < ActiveRecord::Base
238
+ # has_and_belongs_to_many :projects # foreign keys in the join table
239
+ # end
240
+ # class Project < ActiveRecord::Base
241
+ # has_and_belongs_to_many :programmers # foreign keys in the join table
242
+ # end
243
+ #
244
+ # Choosing which way to build a many-to-many relationship is not always simple.
245
+ # If you need to work with the relationship model as its own entity,
246
+ # use #has_many <tt>:through</tt>. Use #has_and_belongs_to_many when working with legacy schemas or when
247
+ # you never work directly with the relationship itself.
248
+ #
249
+ # == Is it a #belongs_to or #has_one association?
250
+ #
251
+ # Both express a 1-1 relationship. The difference is mostly where to place the foreign
252
+ # key, which goes on the table for the class declaring the #belongs_to relationship.
253
+ #
254
+ # class User < ActiveRecord::Base
255
+ # # I reference an account.
256
+ # belongs_to :account
257
+ # end
258
+ #
259
+ # class Account < ActiveRecord::Base
260
+ # # One user references me.
261
+ # has_one :user
262
+ # end
263
+ #
264
+ # The tables for these classes could look something like:
265
+ #
266
+ # CREATE TABLE users (
267
+ # id int NOT NULL auto_increment,
268
+ # account_id int default NULL,
269
+ # name varchar default NULL,
270
+ # PRIMARY KEY (id)
271
+ # )
272
+ #
273
+ # CREATE TABLE accounts (
274
+ # id int NOT NULL auto_increment,
275
+ # name varchar default NULL,
276
+ # PRIMARY KEY (id)
277
+ # )
278
+ #
279
+ # == Unsaved objects and associations
280
+ #
281
+ # You can manipulate objects and associations before they are saved to the database, but
282
+ # there is some special behavior you should be aware of, mostly involving the saving of
283
+ # associated objects.
284
+ #
285
+ # You can set the <tt>:autosave</tt> option on a #has_one, #belongs_to,
286
+ # #has_many, or #has_and_belongs_to_many association. Setting it
287
+ # to +true+ will _always_ save the members, whereas setting it to +false+ will
288
+ # _never_ save the members. More details about <tt>:autosave</tt> option is available at
289
+ # AutosaveAssociation.
290
+ #
291
+ # === One-to-one associations
292
+ #
293
+ # * Assigning an object to a #has_one association automatically saves that object and
294
+ # the object being replaced (if there is one), in order to update their foreign
295
+ # keys - except if the parent object is unsaved (<tt>new_record? == true</tt>).
296
+ # * If either of these saves fail (due to one of the objects being invalid), an
297
+ # ActiveRecord::RecordNotSaved exception is raised and the assignment is
298
+ # cancelled.
299
+ # * If you wish to assign an object to a #has_one association without saving it,
300
+ # use the <tt>#build_association</tt> method (documented below). The object being
301
+ # replaced will still be saved to update its foreign key.
302
+ # * Assigning an object to a #belongs_to association does not save the object, since
303
+ # the foreign key field belongs on the parent. It does not save the parent either.
304
+ #
305
+ # === Collections
306
+ #
307
+ # * Adding an object to a collection (#has_many or #has_and_belongs_to_many) automatically
308
+ # saves that object, except if the parent object (the owner of the collection) is not yet
309
+ # stored in the database.
310
+ # * If saving any of the objects being added to a collection (via <tt>push</tt> or similar)
311
+ # fails, then <tt>push</tt> returns +false+.
312
+ # * If saving fails while replacing the collection (via <tt>association=</tt>), an
313
+ # ActiveRecord::RecordNotSaved exception is raised and the assignment is
314
+ # cancelled.
315
+ # * You can add an object to a collection without automatically saving it by using the
316
+ # <tt>collection.build</tt> method (documented below).
317
+ # * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically
318
+ # saved when the parent is saved.
319
+ #
320
+ # == Customizing the query
321
+ #
322
+ # \Associations are built from <tt>Relation</tt> objects, and you can use the Relation syntax
323
+ # to customize them. For example, to add a condition:
324
+ #
325
+ # class Blog < ActiveRecord::Base
326
+ # has_many :published_posts, -> { where(published: true) }, class_name: 'Post'
327
+ # end
328
+ #
329
+ # Inside the <tt>-> { ... }</tt> block you can use all of the usual Relation methods.
330
+ #
331
+ # === Accessing the owner object
332
+ #
333
+ # Sometimes it is useful to have access to the owner object when building the query. The owner
334
+ # is passed as a parameter to the block. For example, the following association would find all
335
+ # events that occur on the user's birthday:
336
+ #
337
+ # class User < ActiveRecord::Base
338
+ # has_many :birthday_events, ->(user) { where(starts_on: user.birthday) }, class_name: 'Event'
339
+ # end
340
+ #
341
+ # Note: Joining, eager loading and preloading of these associations is not fully possible.
342
+ # These operations happen before instance creation and the scope will be called with a +nil+ argument.
343
+ # This can lead to unexpected behavior and is deprecated.
344
+ #
345
+ # == Association callbacks
346
+ #
347
+ # Similar to the normal callbacks that hook into the life cycle of an Active Record object,
348
+ # you can also define callbacks that get triggered when you add an object to or remove an
349
+ # object from an association collection.
350
+ #
351
+ # class Project
352
+ # has_and_belongs_to_many :developers, after_add: :evaluate_velocity
353
+ #
354
+ # def evaluate_velocity(developer)
355
+ # ...
356
+ # end
357
+ # end
358
+ #
359
+ # It's possible to stack callbacks by passing them as an array. Example:
360
+ #
361
+ # class Project
362
+ # has_and_belongs_to_many :developers,
363
+ # after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
364
+ # end
365
+ #
366
+ # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
367
+ #
368
+ # If any of the +before_add+ callbacks throw an exception, the object will not be
369
+ # added to the collection.
370
+ #
371
+ # Similarly, if any of the +before_remove+ callbacks throw an exception, the object
372
+ # will not be removed from the collection.
373
+ #
374
+ # == Association extensions
375
+ #
376
+ # The proxy objects that control the access to associations can be extended through anonymous
377
+ # modules. This is especially beneficial for adding new finders, creators, and other
378
+ # factory-type methods that are only used as part of this association.
379
+ #
380
+ # class Account < ActiveRecord::Base
381
+ # has_many :people do
382
+ # def find_or_create_by_name(name)
383
+ # first_name, last_name = name.split(" ", 2)
384
+ # find_or_create_by(first_name: first_name, last_name: last_name)
385
+ # end
386
+ # end
387
+ # end
388
+ #
389
+ # person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
390
+ # person.first_name # => "David"
391
+ # person.last_name # => "Heinemeier Hansson"
392
+ #
393
+ # If you need to share the same extensions between many associations, you can use a named
394
+ # extension module.
395
+ #
396
+ # module FindOrCreateByNameExtension
397
+ # def find_or_create_by_name(name)
398
+ # first_name, last_name = name.split(" ", 2)
399
+ # find_or_create_by(first_name: first_name, last_name: last_name)
400
+ # end
401
+ # end
402
+ #
403
+ # class Account < ActiveRecord::Base
404
+ # has_many :people, -> { extending FindOrCreateByNameExtension }
405
+ # end
406
+ #
407
+ # class Company < ActiveRecord::Base
408
+ # has_many :people, -> { extending FindOrCreateByNameExtension }
409
+ # end
410
+ #
411
+ # Some extensions can only be made to work with knowledge of the association's internals.
412
+ # Extensions can access relevant state using the following methods (where +items+ is the
413
+ # name of the association):
414
+ #
415
+ # * <tt>record.association(:items).owner</tt> - Returns the object the association is part of.
416
+ # * <tt>record.association(:items).reflection</tt> - Returns the reflection object that describes the association.
417
+ # * <tt>record.association(:items).target</tt> - Returns the associated object for #belongs_to and #has_one, or
418
+ # the collection of associated objects for #has_many and #has_and_belongs_to_many.
419
+ #
420
+ # However, inside the actual extension code, you will not have access to the <tt>record</tt> as
421
+ # above. In this case, you can access <tt>proxy_association</tt>. For example,
422
+ # <tt>record.association(:items)</tt> and <tt>record.items.proxy_association</tt> will return
423
+ # the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside
424
+ # association extensions.
425
+ #
426
+ # == Association Join Models
427
+ #
428
+ # Has Many associations can be configured with the <tt>:through</tt> option to use an
429
+ # explicit join model to retrieve the data. This operates similarly to a
430
+ # #has_and_belongs_to_many association. The advantage is that you're able to add validations,
431
+ # callbacks, and extra attributes on the join model. Consider the following schema:
432
+ #
433
+ # class Author < ActiveRecord::Base
434
+ # has_many :authorships
435
+ # has_many :books, through: :authorships
436
+ # end
437
+ #
438
+ # class Authorship < ActiveRecord::Base
439
+ # belongs_to :author
440
+ # belongs_to :book
441
+ # end
442
+ #
443
+ # @author = Author.first
444
+ # @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to
445
+ # @author.books # selects all books by using the Authorship join model
446
+ #
447
+ # You can also go through a #has_many association on the join model:
448
+ #
449
+ # class Firm < ActiveRecord::Base
450
+ # has_many :clients
451
+ # has_many :invoices, through: :clients
452
+ # end
453
+ #
454
+ # class Client < ActiveRecord::Base
455
+ # belongs_to :firm
456
+ # has_many :invoices
457
+ # end
458
+ #
459
+ # class Invoice < ActiveRecord::Base
460
+ # belongs_to :client
461
+ # end
462
+ #
463
+ # @firm = Firm.first
464
+ # @firm.clients.flat_map { |c| c.invoices } # select all invoices for all clients of the firm
465
+ # @firm.invoices # selects all invoices by going through the Client join model
466
+ #
467
+ # Similarly you can go through a #has_one association on the join model:
468
+ #
469
+ # class Group < ActiveRecord::Base
470
+ # has_many :users
471
+ # has_many :avatars, through: :users
472
+ # end
473
+ #
474
+ # class User < ActiveRecord::Base
475
+ # belongs_to :group
476
+ # has_one :avatar
477
+ # end
478
+ #
479
+ # class Avatar < ActiveRecord::Base
480
+ # belongs_to :user
481
+ # end
482
+ #
483
+ # @group = Group.first
484
+ # @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
485
+ # @group.avatars # selects all avatars by going through the User join model.
486
+ #
487
+ # An important caveat with going through #has_one or #has_many associations on the
488
+ # join model is that these associations are *read-only*. For example, the following
489
+ # would not work following the previous example:
490
+ #
491
+ # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
492
+ # @group.avatars.delete(@group.avatars.last) # so would this
493
+ #
494
+ # == Setting Inverses
495
+ #
496
+ # If you are using a #belongs_to on the join model, it is a good idea to set the
497
+ # <tt>:inverse_of</tt> option on the #belongs_to, which will mean that the following example
498
+ # works correctly (where <tt>tags</tt> is a #has_many <tt>:through</tt> association):
499
+ #
500
+ # @post = Post.first
501
+ # @tag = @post.tags.build name: "ruby"
502
+ # @tag.save
503
+ #
504
+ # The last line ought to save the through record (a <tt>Tagging</tt>). This will only work if the
505
+ # <tt>:inverse_of</tt> is set:
506
+ #
507
+ # class Tagging < ActiveRecord::Base
508
+ # belongs_to :post
509
+ # belongs_to :tag, inverse_of: :taggings
510
+ # end
511
+ #
512
+ # If you do not set the <tt>:inverse_of</tt> record, the association will
513
+ # do its best to match itself up with the correct inverse. Automatic
514
+ # inverse detection only works on #has_many, #has_one, and
515
+ # #belongs_to associations.
516
+ #
517
+ # Extra options on the associations, as defined in the
518
+ # <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will
519
+ # also prevent the association's inverse from being found automatically.
520
+ #
521
+ # The automatic guessing of the inverse association uses a heuristic based
522
+ # on the name of the class, so it may not work for all associations,
523
+ # especially the ones with non-standard names.
524
+ #
525
+ # You can turn off the automatic detection of inverse associations by setting
526
+ # the <tt>:inverse_of</tt> option to <tt>false</tt> like so:
527
+ #
528
+ # class Tagging < ActiveRecord::Base
529
+ # belongs_to :tag, inverse_of: false
530
+ # end
531
+ #
532
+ # == Nested \Associations
533
+ #
534
+ # You can actually specify *any* association with the <tt>:through</tt> option, including an
535
+ # association which has a <tt>:through</tt> option itself. For example:
536
+ #
537
+ # class Author < ActiveRecord::Base
538
+ # has_many :posts
539
+ # has_many :comments, through: :posts
540
+ # has_many :commenters, through: :comments
541
+ # end
542
+ #
543
+ # class Post < ActiveRecord::Base
544
+ # has_many :comments
545
+ # end
546
+ #
547
+ # class Comment < ActiveRecord::Base
548
+ # belongs_to :commenter
549
+ # end
550
+ #
551
+ # @author = Author.first
552
+ # @author.commenters # => People who commented on posts written by the author
553
+ #
554
+ # An equivalent way of setting up this association this would be:
555
+ #
556
+ # class Author < ActiveRecord::Base
557
+ # has_many :posts
558
+ # has_many :commenters, through: :posts
559
+ # end
560
+ #
561
+ # class Post < ActiveRecord::Base
562
+ # has_many :comments
563
+ # has_many :commenters, through: :comments
564
+ # end
565
+ #
566
+ # class Comment < ActiveRecord::Base
567
+ # belongs_to :commenter
568
+ # end
569
+ #
570
+ # When using a nested association, you will not be able to modify the association because there
571
+ # is not enough information to know what modification to make. For example, if you tried to
572
+ # add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
573
+ # intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
574
+ #
575
+ # == Polymorphic \Associations
576
+ #
577
+ # Polymorphic associations on models are not restricted on what types of models they
578
+ # can be associated with. Rather, they specify an interface that a #has_many association
579
+ # must adhere to.
580
+ #
581
+ # class Asset < ActiveRecord::Base
582
+ # belongs_to :attachable, polymorphic: true
583
+ # end
584
+ #
585
+ # class Post < ActiveRecord::Base
586
+ # has_many :assets, as: :attachable # The :as option specifies the polymorphic interface to use.
587
+ # end
588
+ #
589
+ # @asset.attachable = @post
590
+ #
591
+ # This works by using a type column in addition to a foreign key to specify the associated
592
+ # record. In the Asset example, you'd need an +attachable_id+ integer column and an
593
+ # +attachable_type+ string column.
594
+ #
595
+ # Using polymorphic associations in combination with single table inheritance (STI) is
596
+ # a little tricky. In order for the associations to work as expected, ensure that you
597
+ # store the base model for the STI models in the type column of the polymorphic
598
+ # association. To continue with the asset example above, suppose there are guest posts
599
+ # and member posts that use the posts table for STI. In this case, there must be a +type+
600
+ # column in the posts table.
601
+ #
602
+ # Note: The <tt>attachable_type=</tt> method is being called when assigning an +attachable+.
603
+ # The +class_name+ of the +attachable+ is passed as a String.
604
+ #
605
+ # class Asset < ActiveRecord::Base
606
+ # belongs_to :attachable, polymorphic: true
607
+ #
608
+ # def attachable_type=(class_name)
609
+ # super(class_name.constantize.base_class.to_s)
610
+ # end
611
+ # end
612
+ #
613
+ # class Post < ActiveRecord::Base
614
+ # # because we store "Post" in attachable_type now dependent: :destroy will work
615
+ # has_many :assets, as: :attachable, dependent: :destroy
616
+ # end
617
+ #
618
+ # class GuestPost < Post
619
+ # end
620
+ #
621
+ # class MemberPost < Post
622
+ # end
623
+ #
624
+ # == Caching
625
+ #
626
+ # All of the methods are built on a simple caching principle that will keep the result
627
+ # of the last query around unless specifically instructed not to. The cache is even
628
+ # shared across methods to make it even cheaper to use the macro-added methods without
629
+ # worrying too much about performance at the first go.
630
+ #
631
+ # project.milestones # fetches milestones from the database
632
+ # project.milestones.size # uses the milestone cache
633
+ # project.milestones.empty? # uses the milestone cache
634
+ # project.milestones(true).size # fetches milestones from the database
635
+ # project.milestones # uses the milestone cache
636
+ #
637
+ # == Eager loading of associations
638
+ #
639
+ # Eager loading is a way to find objects of a certain class and a number of named associations.
640
+ # It is one of the easiest ways to prevent the dreaded N+1 problem in which fetching 100
641
+ # posts that each need to display their author triggers 101 database queries. Through the
642
+ # use of eager loading, the number of queries will be reduced from 101 to 2.
643
+ #
644
+ # class Post < ActiveRecord::Base
645
+ # belongs_to :author
646
+ # has_many :comments
647
+ # end
648
+ #
649
+ # Consider the following loop using the class above:
650
+ #
651
+ # Post.all.each do |post|
652
+ # puts "Post: " + post.title
653
+ # puts "Written by: " + post.author.name
654
+ # puts "Last comment on: " + post.comments.first.created_on
655
+ # end
656
+ #
657
+ # To iterate over these one hundred posts, we'll generate 201 database queries. Let's
658
+ # first just optimize it for retrieving the author:
659
+ #
660
+ # Post.includes(:author).each do |post|
661
+ #
662
+ # This references the name of the #belongs_to association that also used the <tt>:author</tt>
663
+ # symbol. After loading the posts, +find+ will collect the +author_id+ from each one and load
664
+ # all of the referenced authors with one query. Doing so will cut down the number of queries
665
+ # from 201 to 102.
666
+ #
667
+ # We can improve upon the situation further by referencing both associations in the finder with:
668
+ #
669
+ # Post.includes(:author, :comments).each do |post|
670
+ #
671
+ # This will load all comments with a single query. This reduces the total number of queries
672
+ # to 3. In general, the number of queries will be 1 plus the number of associations
673
+ # named (except if some of the associations are polymorphic #belongs_to - see below).
674
+ #
675
+ # To include a deep hierarchy of associations, use a hash:
676
+ #
677
+ # Post.includes(:author, { comments: { author: :gravatar } }).each do |post|
678
+ #
679
+ # The above code will load all the comments and all of their associated
680
+ # authors and gravatars. You can mix and match any combination of symbols,
681
+ # arrays, and hashes to retrieve the associations you want to load.
682
+ #
683
+ # All of this power shouldn't fool you into thinking that you can pull out huge amounts
684
+ # of data with no performance penalty just because you've reduced the number of queries.
685
+ # The database still needs to send all the data to Active Record and it still needs to
686
+ # be processed. So it's no catch-all for performance problems, but it's a great way to
687
+ # cut down on the number of queries in a situation as the one described above.
688
+ #
689
+ # Since only one table is loaded at a time, conditions or orders cannot reference tables
690
+ # other than the main one. If this is the case, Active Record falls back to the previously
691
+ # used <tt>LEFT OUTER JOIN</tt> based strategy. For example:
692
+ #
693
+ # Post.includes([:author, :comments]).where(['comments.approved = ?', true])
694
+ #
695
+ # This will result in a single SQL query with joins along the lines of:
696
+ # <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
697
+ # <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions
698
+ # like this can have unintended consequences.
699
+ # In the above example, posts with no approved comments are not returned at all because
700
+ # the conditions apply to the SQL statement as a whole and not just to the association.
701
+ #
702
+ # You must disambiguate column references for this fallback to happen, for example
703
+ # <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
704
+ #
705
+ # If you want to load all posts (including posts with no approved comments), then write
706
+ # your own <tt>LEFT OUTER JOIN</tt> query using <tt>ON</tt>:
707
+ #
708
+ # Post.joins("LEFT OUTER JOIN comments ON comments.post_id = posts.id AND comments.approved = '1'")
709
+ #
710
+ # In this case, it is usually more natural to include an association which has conditions defined on it:
711
+ #
712
+ # class Post < ActiveRecord::Base
713
+ # has_many :approved_comments, -> { where(approved: true) }, class_name: 'Comment'
714
+ # end
715
+ #
716
+ # Post.includes(:approved_comments)
717
+ #
718
+ # This will load posts and eager load the +approved_comments+ association, which contains
719
+ # only those comments that have been approved.
720
+ #
721
+ # If you eager load an association with a specified <tt>:limit</tt> option, it will be ignored,
722
+ # returning all the associated objects:
723
+ #
724
+ # class Picture < ActiveRecord::Base
725
+ # has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment'
726
+ # end
727
+ #
728
+ # Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
729
+ #
730
+ # Eager loading is supported with polymorphic associations.
731
+ #
732
+ # class Address < ActiveRecord::Base
733
+ # belongs_to :addressable, polymorphic: true
734
+ # end
735
+ #
736
+ # A call that tries to eager load the addressable model
737
+ #
738
+ # Address.includes(:addressable)
739
+ #
740
+ # This will execute one query to load the addresses and load the addressables with one
741
+ # query per addressable type.
742
+ # For example, if all the addressables are either of class Person or Company, then a total
743
+ # of 3 queries will be executed. The list of addressable types to load is determined on
744
+ # the back of the addresses loaded. This is not supported if Active Record has to fallback
745
+ # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError.
746
+ # The reason is that the parent model's type is a column value so its corresponding table
747
+ # name cannot be put in the +FROM+/+JOIN+ clauses of that query.
748
+ #
749
+ # == Table Aliasing
750
+ #
751
+ # Active Record uses table aliasing in the case that a table is referenced multiple times
752
+ # in a join. If a table is referenced only once, the standard table name is used. The
753
+ # second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>.
754
+ # Indexes are appended for any more successive uses of the table name.
755
+ #
756
+ # Post.joins(:comments)
757
+ # # => SELECT ... FROM posts INNER JOIN comments ON ...
758
+ # Post.joins(:special_comments) # STI
759
+ # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment'
760
+ # Post.joins(:comments, :special_comments) # special_comments is the reflection name, posts is the parent table name
761
+ # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts
762
+ #
763
+ # Acts as tree example:
764
+ #
765
+ # TreeMixin.joins(:children)
766
+ # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
767
+ # TreeMixin.joins(children: :parent)
768
+ # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
769
+ # INNER JOIN parents_mixins ...
770
+ # TreeMixin.joins(children: {parent: :children})
771
+ # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
772
+ # INNER JOIN parents_mixins ...
773
+ # INNER JOIN mixins childrens_mixins_2
774
+ #
775
+ # Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
776
+ #
777
+ # Post.joins(:categories)
778
+ # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
779
+ # Post.joins(categories: :posts)
780
+ # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
781
+ # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
782
+ # Post.joins(categories: {posts: :categories})
783
+ # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
784
+ # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
785
+ # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
786
+ #
787
+ # If you wish to specify your own custom joins using ActiveRecord::QueryMethods#joins method, those table
788
+ # names will take precedence over the eager associations:
789
+ #
790
+ # Post.joins(:comments).joins("inner join comments ...")
791
+ # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ...
792
+ # Post.joins(:comments, :special_comments).joins("inner join comments ...")
793
+ # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ...
794
+ # INNER JOIN comments special_comments_posts ...
795
+ # INNER JOIN comments ...
796
+ #
797
+ # Table aliases are automatically truncated according to the maximum length of table identifiers
798
+ # according to the specific database.
799
+ #
800
+ # == Modules
801
+ #
802
+ # By default, associations will look for objects within the current module scope. Consider:
803
+ #
804
+ # module MyApplication
805
+ # module Business
806
+ # class Firm < ActiveRecord::Base
807
+ # has_many :clients
808
+ # end
809
+ #
810
+ # class Client < ActiveRecord::Base; end
811
+ # end
812
+ # end
813
+ #
814
+ # When <tt>Firm#clients</tt> is called, it will in turn call
815
+ # <tt>MyApplication::Business::Client.find_all_by_firm_id(firm.id)</tt>.
816
+ # If you want to associate with a class in another module scope, this can be done by
817
+ # specifying the complete class name.
818
+ #
819
+ # module MyApplication
820
+ # module Business
821
+ # class Firm < ActiveRecord::Base; end
822
+ # end
823
+ #
824
+ # module Billing
825
+ # class Account < ActiveRecord::Base
826
+ # belongs_to :firm, class_name: "MyApplication::Business::Firm"
827
+ # end
828
+ # end
829
+ # end
830
+ #
831
+ # == Bi-directional associations
832
+ #
833
+ # When you specify an association, there is usually an association on the associated model
834
+ # that specifies the same relationship in reverse. For example, with the following models:
835
+ #
836
+ # class Dungeon < ActiveRecord::Base
837
+ # has_many :traps
838
+ # has_one :evil_wizard
839
+ # end
840
+ #
841
+ # class Trap < ActiveRecord::Base
842
+ # belongs_to :dungeon
843
+ # end
844
+ #
845
+ # class EvilWizard < ActiveRecord::Base
846
+ # belongs_to :dungeon
847
+ # end
848
+ #
849
+ # The +traps+ association on +Dungeon+ and the +dungeon+ association on +Trap+ are
850
+ # the inverse of each other, and the inverse of the +dungeon+ association on +EvilWizard+
851
+ # is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default,
852
+ # Active Record can guess the inverse of the association based on the name
853
+ # of the class. The result is the following:
854
+ #
855
+ # d = Dungeon.first
856
+ # t = d.traps.first
857
+ # d.object_id == t.dungeon.object_id # => true
858
+ #
859
+ # The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to
860
+ # the same in-memory instance since the association matches the name of the class.
861
+ # The result would be the same if we added +:inverse_of+ to our model definitions:
862
+ #
863
+ # class Dungeon < ActiveRecord::Base
864
+ # has_many :traps, inverse_of: :dungeon
865
+ # has_one :evil_wizard, inverse_of: :dungeon
866
+ # end
867
+ #
868
+ # class Trap < ActiveRecord::Base
869
+ # belongs_to :dungeon, inverse_of: :traps
870
+ # end
871
+ #
872
+ # class EvilWizard < ActiveRecord::Base
873
+ # belongs_to :dungeon, inverse_of: :evil_wizard
874
+ # end
875
+ #
876
+ # There are limitations to <tt>:inverse_of</tt> support:
877
+ #
878
+ # * does not work with <tt>:through</tt> associations.
879
+ # * does not work with <tt>:polymorphic</tt> associations.
880
+ # * inverse associations for #belongs_to associations #has_many are ignored.
881
+ #
882
+ # For more information, see the documentation for the +:inverse_of+ option.
883
+ #
884
+ # == Deleting from associations
885
+ #
886
+ # === Dependent associations
887
+ #
888
+ # #has_many, #has_one, and #belongs_to associations support the <tt>:dependent</tt> option.
889
+ # This allows you to specify that associated records should be deleted when the owner is
890
+ # deleted.
891
+ #
892
+ # For example:
893
+ #
894
+ # class Author
895
+ # has_many :posts, dependent: :destroy
896
+ # end
897
+ # Author.find(1).destroy # => Will destroy all of the author's posts, too
898
+ #
899
+ # The <tt>:dependent</tt> option can have different values which specify how the deletion
900
+ # is done. For more information, see the documentation for this option on the different
901
+ # specific association types. When no option is given, the behavior is to do nothing
902
+ # with the associated records when destroying a record.
903
+ #
904
+ # Note that <tt>:dependent</tt> is implemented using Rails' callback
905
+ # system, which works by processing callbacks in order. Therefore, other
906
+ # callbacks declared either before or after the <tt>:dependent</tt> option
907
+ # can affect what it does.
908
+ #
909
+ # Note that <tt>:dependent</tt> option is ignored for #has_one <tt>:through</tt> associations.
910
+ #
911
+ # === Delete or destroy?
912
+ #
913
+ # #has_many and #has_and_belongs_to_many associations have the methods <tt>destroy</tt>,
914
+ # <tt>delete</tt>, <tt>destroy_all</tt> and <tt>delete_all</tt>.
915
+ #
916
+ # For #has_and_belongs_to_many, <tt>delete</tt> and <tt>destroy</tt> are the same: they
917
+ # cause the records in the join table to be removed.
918
+ #
919
+ # For #has_many, <tt>destroy</tt> and <tt>destroy_all</tt> will always call the <tt>destroy</tt> method of the
920
+ # record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either
921
+ # do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
922
+ # if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
923
+ # The default strategy is to do nothing (leave the foreign keys with the parent ids set), except for
924
+ # #has_many <tt>:through</tt>, where the default strategy is <tt>delete_all</tt> (delete
925
+ # the join records, without running their callbacks).
926
+ #
927
+ # There is also a <tt>clear</tt> method which is the same as <tt>delete_all</tt>, except that
928
+ # it returns the association rather than the records which have been deleted.
929
+ #
930
+ # === What gets deleted?
931
+ #
932
+ # There is a potential pitfall here: #has_and_belongs_to_many and #has_many <tt>:through</tt>
933
+ # associations have records in join tables, as well as the associated records. So when we
934
+ # call one of these deletion methods, what exactly should be deleted?
935
+ #
936
+ # The answer is that it is assumed that deletion on an association is about removing the
937
+ # <i>link</i> between the owner and the associated object(s), rather than necessarily the
938
+ # associated objects themselves. So with #has_and_belongs_to_many and #has_many
939
+ # <tt>:through</tt>, the join records will be deleted, but the associated records won't.
940
+ #
941
+ # This makes sense if you think about it: if you were to call <tt>post.tags.delete(Tag.find_by(name: 'food'))</tt>
942
+ # you would want the 'food' tag to be unlinked from the post, rather than for the tag itself
943
+ # to be removed from the database.
944
+ #
945
+ # However, there are examples where this strategy doesn't make sense. For example, suppose
946
+ # a person has many projects, and each project has many tasks. If we deleted one of a person's
947
+ # tasks, we would probably not want the project to be deleted. In this scenario, the delete method
948
+ # won't actually work: it can only be used if the association on the join model is a
949
+ # #belongs_to. In other situations you are expected to perform operations directly on
950
+ # either the associated records or the <tt>:through</tt> association.
951
+ #
952
+ # With a regular #has_many there is no distinction between the "associated records"
953
+ # and the "link", so there is only one choice for what gets deleted.
954
+ #
955
+ # With #has_and_belongs_to_many and #has_many <tt>:through</tt>, if you want to delete the
956
+ # associated records themselves, you can always do something along the lines of
957
+ # <tt>person.tasks.each(&:destroy)</tt>.
958
+ #
959
+ # == Type safety with ActiveRecord::AssociationTypeMismatch
960
+ #
961
+ # If you attempt to assign an object to an association that doesn't match the inferred
962
+ # or specified <tt>:class_name</tt>, you'll get an ActiveRecord::AssociationTypeMismatch.
963
+ #
964
+ # == Options
965
+ #
966
+ # All of the association macros can be specialized through options. This makes cases
967
+ # more complex than the simple and guessable ones possible.
968
+ module ClassMethods
969
+ # Specifies a one-to-many association. The following methods for retrieval and query of
970
+ # collections of associated objects will be added:
971
+ #
972
+ # +collection+ is a placeholder for the symbol passed as the +name+ argument, so
973
+ # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
974
+ #
975
+ # [collection(force_reload = false)]
976
+ # Returns an array of all the associated objects.
977
+ # An empty array is returned if none are found.
978
+ # [collection<<(object, ...)]
979
+ # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
980
+ # Note that this operation instantly fires update SQL without waiting for the save or update call on the
981
+ # parent object, unless the parent object is a new record.
982
+ # This will also run validations and callbacks of associated object(s).
983
+ # [collection.delete(object, ...)]
984
+ # Removes one or more objects from the collection by setting their foreign keys to +NULL+.
985
+ # Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>,
986
+ # and deleted if they're associated with <tt>dependent: :delete_all</tt>.
987
+ #
988
+ # If the <tt>:through</tt> option is used, then the join records are deleted (rather than
989
+ # nullified) by default, but you can specify <tt>dependent: :destroy</tt> or
990
+ # <tt>dependent: :nullify</tt> to override this.
991
+ # [collection.destroy(object, ...)]
992
+ # Removes one or more objects from the collection by running <tt>destroy</tt> on
993
+ # each record, regardless of any dependent option, ensuring callbacks are run.
994
+ #
995
+ # If the <tt>:through</tt> option is used, then the join records are destroyed
996
+ # instead, not the objects themselves.
997
+ # [collection=objects]
998
+ # Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
999
+ # option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
1000
+ # direct by default. You can specify <tt>dependent: :destroy</tt> or
1001
+ # <tt>dependent: :nullify</tt> to override this.
1002
+ # [collection_singular_ids]
1003
+ # Returns an array of the associated objects' ids
1004
+ # [collection_singular_ids=ids]
1005
+ # Replace the collection with the objects identified by the primary keys in +ids+. This
1006
+ # method loads the models and calls <tt>collection=</tt>. See above.
1007
+ # [collection.clear]
1008
+ # Removes every object from the collection. This destroys the associated objects if they
1009
+ # are associated with <tt>dependent: :destroy</tt>, deletes them directly from the
1010
+ # database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
1011
+ # If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
1012
+ # Join models are directly deleted.
1013
+ # [collection.empty?]
1014
+ # Returns +true+ if there are no associated objects.
1015
+ # [collection.size]
1016
+ # Returns the number of associated objects.
1017
+ # [collection.find(...)]
1018
+ # Finds an associated object according to the same rules as ActiveRecord::FinderMethods#find.
1019
+ # [collection.exists?(...)]
1020
+ # Checks whether an associated object with the given conditions exists.
1021
+ # Uses the same rules as ActiveRecord::FinderMethods#exists?.
1022
+ # [collection.build(attributes = {}, ...)]
1023
+ # Returns one or more new objects of the collection type that have been instantiated
1024
+ # with +attributes+ and linked to this object through a foreign key, but have not yet
1025
+ # been saved.
1026
+ # [collection.create(attributes = {})]
1027
+ # Returns a new object of the collection type that has been instantiated
1028
+ # with +attributes+, linked to this object through a foreign key, and that has already
1029
+ # been saved (if it passed the validation). *Note*: This only works if the base model
1030
+ # already exists in the DB, not if it is a new (unsaved) record!
1031
+ # [collection.create!(attributes = {})]
1032
+ # Does the same as <tt>collection.create</tt>, but raises ActiveRecord::RecordInvalid
1033
+ # if the record is invalid.
1034
+ #
1035
+ # === Example
1036
+ #
1037
+ # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
1038
+ # * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
1039
+ # * <tt>Firm#clients<<</tt>
1040
+ # * <tt>Firm#clients.delete</tt>
1041
+ # * <tt>Firm#clients.destroy</tt>
1042
+ # * <tt>Firm#clients=</tt>
1043
+ # * <tt>Firm#client_ids</tt>
1044
+ # * <tt>Firm#client_ids=</tt>
1045
+ # * <tt>Firm#clients.clear</tt>
1046
+ # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
1047
+ # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
1048
+ # * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
1049
+ # * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
1050
+ # * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
1051
+ # * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
1052
+ # * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
1053
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
1054
+ #
1055
+ # === Scopes
1056
+ #
1057
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
1058
+ # lambda) to retrieve a specific set of records or customize the generated
1059
+ # query when you access the associated collection.
1060
+ #
1061
+ # Scope examples:
1062
+ # has_many :comments, -> { where(author_id: 1) }
1063
+ # has_many :employees, -> { joins(:address) }
1064
+ # has_many :posts, ->(post) { where("max_post_length > ?", post.length) }
1065
+ #
1066
+ # === Extensions
1067
+ #
1068
+ # The +extension+ argument allows you to pass a block into a has_many
1069
+ # association. This is useful for adding new finders, creators and other
1070
+ # factory-type methods to be used as part of the association.
1071
+ #
1072
+ # Extension examples:
1073
+ # has_many :employees do
1074
+ # def find_or_create_by_name(name)
1075
+ # first_name, last_name = name.split(" ", 2)
1076
+ # find_or_create_by(first_name: first_name, last_name: last_name)
1077
+ # end
1078
+ # end
1079
+ #
1080
+ # === Options
1081
+ # [:class_name]
1082
+ # Specify the class name of the association. Use it only if that name can't be inferred
1083
+ # from the association name. So <tt>has_many :products</tt> will by default be linked
1084
+ # to the +Product+ class, but if the real class name is +SpecialProduct+, you'll have to
1085
+ # specify it with this option.
1086
+ # [:foreign_key]
1087
+ # Specify the foreign key used for the association. By default this is guessed to be the name
1088
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_many
1089
+ # association will use "person_id" as the default <tt>:foreign_key</tt>.
1090
+ # [:foreign_type]
1091
+ # Specify the column used to store the associated object's type, if this is a polymorphic
1092
+ # association. By default this is guessed to be the name of the polymorphic association
1093
+ # specified on "as" option with a "_type" suffix. So a class that defines a
1094
+ # <tt>has_many :tags, as: :taggable</tt> association will use "taggable_type" as the
1095
+ # default <tt>:foreign_type</tt>.
1096
+ # [:primary_key]
1097
+ # Specify the name of the column to use as the primary key for the association. By default this is +id+.
1098
+ # [:dependent]
1099
+ # Controls what happens to the associated objects when
1100
+ # their owner is destroyed. Note that these are implemented as
1101
+ # callbacks, and Rails executes callbacks in order. Therefore, other
1102
+ # similar callbacks may affect the <tt>:dependent</tt> behavior, and the
1103
+ # <tt>:dependent</tt> behavior may affect other callbacks.
1104
+ #
1105
+ # * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
1106
+ # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
1107
+ # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
1108
+ # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records.
1109
+ # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects.
1110
+ #
1111
+ # If using with the <tt>:through</tt> option, the association on the join model must be
1112
+ # a #belongs_to, and the records which get deleted are the join records, rather than
1113
+ # the associated records.
1114
+ #
1115
+ # If using <tt>dependent: :destroy</tt> on a scoped association, only the scoped objects are destroyed.
1116
+ # For example, if a Post model defines
1117
+ # <tt>has_many :comments, -> { where published: true }, dependent: :destroy</tt> and <tt>destroy</tt> is
1118
+ # called on a post, only published comments are destroyed. This means that any unpublished comments in the
1119
+ # database would still contain a foreign key pointing to the now deleted post.
1120
+ # [:counter_cache]
1121
+ # This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
1122
+ # when you customized the name of your <tt>:counter_cache</tt> on the #belongs_to association.
1123
+ # [:as]
1124
+ # Specifies a polymorphic interface (See #belongs_to).
1125
+ # [:through]
1126
+ # Specifies an association through which to perform the query. This can be any other type
1127
+ # of association, including other <tt>:through</tt> associations. Options for <tt>:class_name</tt>,
1128
+ # <tt>:primary_key</tt> and <tt>:foreign_key</tt> are ignored, as the association uses the
1129
+ # source reflection.
1130
+ #
1131
+ # If the association on the join model is a #belongs_to, the collection can be modified
1132
+ # and the records on the <tt>:through</tt> model will be automatically created and removed
1133
+ # as appropriate. Otherwise, the collection is read-only, so you should manipulate the
1134
+ # <tt>:through</tt> association directly.
1135
+ #
1136
+ # If you are going to modify the association (rather than just read from it), then it is
1137
+ # a good idea to set the <tt>:inverse_of</tt> option on the source association on the
1138
+ # join model. This allows associated records to be built which will automatically create
1139
+ # the appropriate join model records when they are saved. (See the 'Association Join Models'
1140
+ # section above.)
1141
+ # [:source]
1142
+ # Specifies the source association name used by #has_many <tt>:through</tt> queries.
1143
+ # Only use it if the name cannot be inferred from the association.
1144
+ # <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
1145
+ # <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
1146
+ # [:source_type]
1147
+ # Specifies type of the source association used by #has_many <tt>:through</tt> queries where the source
1148
+ # association is a polymorphic #belongs_to.
1149
+ # [:validate]
1150
+ # When set to +true+, validates new objects added to association when saving the parent object. +true+ by default.
1151
+ # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
1152
+ # [:autosave]
1153
+ # If true, always save the associated objects or destroy them if marked for destruction,
1154
+ # when saving the parent object. If false, never save or destroy the associated objects.
1155
+ # By default, only save associated objects that are new records. This option is implemented as a
1156
+ # +before_save+ callback. Because callbacks are run in the order they are defined, associated objects
1157
+ # may need to be explicitly saved in any user-defined +before_save+ callbacks.
1158
+ #
1159
+ # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
1160
+ # <tt>:autosave</tt> to <tt>true</tt>.
1161
+ # [:inverse_of]
1162
+ # Specifies the name of the #belongs_to association on the associated object
1163
+ # that is the inverse of this #has_many association. Does not work in combination
1164
+ # with <tt>:through</tt> or <tt>:as</tt> options.
1165
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1166
+ # [:extend]
1167
+ # Specifies a module or array of modules that will be extended into the association object returned.
1168
+ # Useful for defining methods on associations, especially when they should be shared between multiple
1169
+ # association objects.
1170
+ #
1171
+ # Option examples:
1172
+ # has_many :comments, -> { order("posted_on") }
1173
+ # has_many :comments, -> { includes(:author) }
1174
+ # has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person"
1175
+ # has_many :tracks, -> { order("position") }, dependent: :destroy
1176
+ # has_many :comments, dependent: :nullify
1177
+ # has_many :tags, as: :taggable
1178
+ # has_many :reports, -> { readonly }
1179
+ # has_many :subscribers, through: :subscriptions, source: :user
1180
+ def has_many(name, options = {}, &extension)
1181
+ reflection = Builder::HasMany.build(self, name, options, &extension)
1182
+ Reflection.add_reflection self, name, reflection
1183
+ end
1184
+
1185
+ # Specifies a one-to-one association with another class. This method should only be used
1186
+ # if the other class contains the foreign key. If the current class contains the foreign key,
1187
+ # then you should use #belongs_to instead. See also ActiveRecord::Associations::ClassMethods's overview
1188
+ # on when to use #has_one and when to use #belongs_to.
1189
+ #
1190
+ # The following methods for retrieval and query of a single associated object will be added:
1191
+ #
1192
+ # +association+ is a placeholder for the symbol passed as the +name+ argument, so
1193
+ # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
1194
+ #
1195
+ # [association(force_reload = false)]
1196
+ # Returns the associated object. +nil+ is returned if none is found.
1197
+ # [association=(associate)]
1198
+ # Assigns the associate object, extracts the primary key, sets it as the foreign key,
1199
+ # and saves the associate object. To avoid database inconsistencies, permanently deletes an existing
1200
+ # associated object when assigning a new one, even if the new one isn't saved to database.
1201
+ # [build_association(attributes = {})]
1202
+ # Returns a new object of the associated type that has been instantiated
1203
+ # with +attributes+ and linked to this object through a foreign key, but has not
1204
+ # yet been saved.
1205
+ # [create_association(attributes = {})]
1206
+ # Returns a new object of the associated type that has been instantiated
1207
+ # with +attributes+, linked to this object through a foreign key, and that
1208
+ # has already been saved (if it passed the validation).
1209
+ # [create_association!(attributes = {})]
1210
+ # Does the same as <tt>create_association</tt>, but raises ActiveRecord::RecordInvalid
1211
+ # if the record is invalid.
1212
+ #
1213
+ # === Example
1214
+ #
1215
+ # An Account class declares <tt>has_one :beneficiary</tt>, which will add:
1216
+ # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
1217
+ # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
1218
+ # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
1219
+ # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
1220
+ # * <tt>Account#create_beneficiary!</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save!; b</tt>)
1221
+ #
1222
+ # === Scopes
1223
+ #
1224
+ # You can pass a second argument +scope+ as a callable (i.e. proc or
1225
+ # lambda) to retrieve a specific record or customize the generated query
1226
+ # when you access the associated object.
1227
+ #
1228
+ # Scope examples:
1229
+ # has_one :author, -> { where(comment_id: 1) }
1230
+ # has_one :employer, -> { joins(:company) }
1231
+ # has_one :dob, ->(dob) { where("Date.new(2000, 01, 01) > ?", dob) }
1232
+ #
1233
+ # === Options
1234
+ #
1235
+ # The declaration can also include an +options+ hash to specialize the behavior of the association.
1236
+ #
1237
+ # Options are:
1238
+ # [:class_name]
1239
+ # Specify the class name of the association. Use it only if that name can't be inferred
1240
+ # from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
1241
+ # if the real class name is Person, you'll have to specify it with this option.
1242
+ # [:dependent]
1243
+ # Controls what happens to the associated object when
1244
+ # its owner is destroyed:
1245
+ #
1246
+ # * <tt>:destroy</tt> causes the associated object to also be destroyed
1247
+ # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
1248
+ # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
1249
+ # * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record
1250
+ # * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
1251
+ #
1252
+ # Note that <tt>:dependent</tt> option is ignored when using <tt>:through</tt> option.
1253
+ # [:foreign_key]
1254
+ # Specify the foreign key used for the association. By default this is guessed to be the name
1255
+ # of this class in lower-case and "_id" suffixed. So a Person class that makes a #has_one association
1256
+ # will use "person_id" as the default <tt>:foreign_key</tt>.
1257
+ # [:foreign_type]
1258
+ # Specify the column used to store the associated object's type, if this is a polymorphic
1259
+ # association. By default this is guessed to be the name of the polymorphic association
1260
+ # specified on "as" option with a "_type" suffix. So a class that defines a
1261
+ # <tt>has_one :tag, as: :taggable</tt> association will use "taggable_type" as the
1262
+ # default <tt>:foreign_type</tt>.
1263
+ # [:primary_key]
1264
+ # Specify the method that returns the primary key used for the association. By default this is +id+.
1265
+ # [:as]
1266
+ # Specifies a polymorphic interface (See #belongs_to).
1267
+ # [:through]
1268
+ # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
1269
+ # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
1270
+ # source reflection. You can only use a <tt>:through</tt> query through a #has_one
1271
+ # or #belongs_to association on the join model.
1272
+ # [:source]
1273
+ # Specifies the source association name used by #has_one <tt>:through</tt> queries.
1274
+ # Only use it if the name cannot be inferred from the association.
1275
+ # <tt>has_one :favorite, through: :favorites</tt> will look for a
1276
+ # <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
1277
+ # [:source_type]
1278
+ # Specifies type of the source association used by #has_one <tt>:through</tt> queries where the source
1279
+ # association is a polymorphic #belongs_to.
1280
+ # [:validate]
1281
+ # When set to +true+, validates new objects added to association when saving the parent object. +false+ by default.
1282
+ # If you want to ensure associated objects are revalidated on every update, use +validates_associated+.
1283
+ # [:autosave]
1284
+ # If true, always save the associated object or destroy it if marked for destruction,
1285
+ # when saving the parent object. If false, never save or destroy the associated object.
1286
+ # By default, only save the associated object if it's a new record.
1287
+ #
1288
+ # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
1289
+ # <tt>:autosave</tt> to <tt>true</tt>.
1290
+ # [:inverse_of]
1291
+ # Specifies the name of the #belongs_to association on the associated object
1292
+ # that is the inverse of this #has_one association. Does not work in combination
1293
+ # with <tt>:through</tt> or <tt>:as</tt> options.
1294
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1295
+ # [:required]
1296
+ # When set to +true+, the association will also have its presence validated.
1297
+ # This will validate the association itself, not the id. You can use
1298
+ # +:inverse_of+ to avoid an extra query during validation.
1299
+ #
1300
+ # Option examples:
1301
+ # has_one :credit_card, dependent: :destroy # destroys the associated credit card
1302
+ # has_one :credit_card, dependent: :nullify # updates the associated records foreign
1303
+ # # key value to NULL rather than destroying it
1304
+ # has_one :last_comment, -> { order('posted_on') }, class_name: "Comment"
1305
+ # has_one :project_manager, -> { where(role: 'project_manager') }, class_name: "Person"
1306
+ # has_one :attachment, as: :attachable
1307
+ # has_one :boss, -> { readonly }
1308
+ # has_one :club, through: :membership
1309
+ # has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
1310
+ # has_one :credit_card, required: true
1311
+ def has_one(name, options = {})
1312
+ reflection = Builder::HasOne.build(self, name, options)
1313
+ Reflection.add_reflection self, name, reflection
1314
+ end
1315
+ end
1316
+ end
1317
+ end