belongs_to
- 1.0.0 (0)
- 1.1.6 (14)
- 1.2.6 (0)
- 2.0.3 (21)
- 2.1.0 (38)
- 2.2.1 (7)
- 2.3.8 (27)
- 3.0.0 (19)
- 3.0.9 (-9)
- 3.1.0 (27)
- 3.2.1 (0)
- 3.2.8 (0)
- 3.2.13 (0)
- 4.0.2 (-16)
- 4.1.8 (0)
- 4.2.1 (27)
- 4.2.7 (0)
- 4.2.9 (0)
- 5.0.0.1 (23)
- 5.1.7 (13)
- 5.2.3 (3)
- 6.0.0 (3)
- 6.1.3.1 (19)
- 6.1.7.7 (0)
- 7.0.0 (14)
- 7.1.3.2 (35)
- 7.1.3.4 (0)
- What's this?
belongs_to(association_id, options = {})
public
Adds the following methods for retrieval and query for a single associated object that this object holds an id to. association is replaced with the symbol passed as the first argument, so belongs_to :author would add among others author.nil?.
- association(force_reload = false) - returns the associated object. Nil is returned if none is found.
- association=(associate) - assigns the associate object, extracts the primary key, and sets it as the foreign key.
- association.nil? - returns true if there is no associated object.
- build_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key but has not yet been saved.
- create_association(attributes = {}) - returns a new object of the associated type that has been instantiated with attributes and linked to this object through a foreign key and that has already been saved (if it passed the validation).
Example: A Post class declares belongs_to :author, which will add:
- Post#author (similar to Author.find(author_id))
- Post#author=(author) (similar to post.author_id = author.id)
- Post#author? (similar to post.author == some_author)
- Post#author.nil?
- Post#build_author (similar to post.author = Author.new)
- Post#create_author (similar to post.author = Author.new; post.author.save; post.author)
The declaration can also include an options hash to specialize the behavior of the association.
Options are:
- :class_name - specify the class name of the association. Use it only if that name can’t be inferred from the association name. So has_one :author will by default be linked to the Author class, but if the real class name is Person, you’ll have to specify it with this option.
- :conditions - specify the conditions that the associated object must meet in order to be included as a "WHERE" sql fragment, such as "authorized = 1".
- :order - specify the order from which the associated object will be picked at the top. Specified as an "ORDER BY" sql fragment, such as "last_name, first_name DESC"
- :foreign_key - specify the foreign key used for the association. By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed. So a Person class that makes a belongs_to association to a Boss class will use "boss_id" as the default foreign_key.
- :counter_cache - caches the number of belonging objects on the associate class through use of increment_counter and decrement_counter. The counter cache is incremented when an object of this class is created and decremented when it’s destroyed. This requires that a column named "#{table_name}_count" (such as comments_count for a belonging Comment class) is used on the associate class (such as a Post class). You can also specify a custom counter cache column by given that name instead of a true/false value to this option (e.g., :counter_cache => :my_custom_counter.)
- :include - specify second-order associations that should be eager loaded when this object is loaded.
- :polymorphic - specify this association is a polymorphic association by passing true.
Option examples:
belongs_to :firm, :foreign_key => "client_of" belongs_to :author, :class_name => "Person", :foreign_key => "author_id" belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id", :conditions => 'discounts > #{payments_count}' belongs_to :attachable, :polymorphic => true
Undocumented :inverse_of option
Support for the :inverse_of option was backported to 2.3.6+.
Here’s the description from the original commit: http://github.com/rails/rails/commit/ccea98389abbf150b886c9f964b1def47f00f237
You can now add an :inverse_of option to has_one, has_many and belongs_to associations. This is best described with an example:
class Man < ActiveRecord::Base has_one :face, :inverse_of => :man end class Face < ActiveRecord::Base belongs_to :man, :inverse_of => :face end m = Man.first f = m.face
Without :inverse_of m and f.man would be different instances of the same object (f.man being pulled from the database again). With these new :inverse_of options m and f.man are the same in memory instance.
Currently :inverse_of supports has_one and has_many (but not the :through variants) associations. It also supplies inverse support for belongs_to associations where the inverse is a has_one and it’s not a polymorphic.
Can be extended but only with a module
Although not documented, belongs_to does support Association Extensions however it doesn’t accept a block like has_many does. So you can’t do this:
class Account < ActiveRecord::Base belongs_to :person do def do_something_funky # Some exciting code end end end
but you can do this:
module FunkyExtension def do_something_funky # Some exciting code end end class Account < ActiveRecord::Base belongs_to :person, :extend => FunkyExtension end
And then call it like this:
@account = Account.first @account.person.do_something_funky
Extend with an anonymous module
You can extend with an anonymous module for one-off cases that won’t be repeated:
belongs_to :container, :polymorphic => true, :extend => ( Module.new do def find_target ... end end )
The parentheses are important, will fail silently without them.
Easy workaround for missing :through option
Note that belongs_to does not support :through option like has_many (although IMHO it would make sense in some cases), but you can easily simulate it with delegate.
For example:
class Person < ActiveRecord::Base belongs_to :team ... end class Task < ActiveRecord::Base belongs_to :person delegate :team, :to => :person end
There is of course more ways to do it, but this seems to be the easiest to me.
Exension module patch
I’d say its just an oversight.
If you’d like to see all associations get equal support for extension modules take a look at this patch and give it a +1.
Caveat and design hints regarding :counter_cache
(From Obie Fernandez/ The Rails Way, ISBN 978-0321445612. Thanks Obie!)
This caveat:
The value of the counter cache column must be set to zero by default in the database! Otherwise the counter caching won’t work at all. It’s because the way that Rails implements the counter caching behavior is by adding a simple callback that goes directly to the database with an UPDATE command and increments the value of the counter.
And these tips:
If a significant percentage of your association collections will be empty at any given moment, you can optimize performance at the cost of some extra database storage by using counter caches liberally. The reason is that when the counter cache attribute is at zero, Rails won’t even try to query the database for the associated records!
If you’re not careful, and neglect to set a default value of 0 for the counter cache column on the database, or misspell the column name, the counter cache will still seem to work! There is a magic method on all classes with has_many associations called collection_count, just like the counter cache. It will return a correct count value if you don’t have a counter cache option set or the counter cache column value is null!
Patch looks good.
I assume commenting right below the ticket is the “+1” action? :) Thanks for the reply and patch efforts!
:foreign_type option
I’m not sure if this has always been around but in 2.3, belongs_to takes a :foreign_type option on polymorphic associations. This behaves the same way as :foreign_key but for the type field.
missing :through option
So the way to do the equivalent of a has_many :through is to use has_one :through, with the expected names.
so using the other example we could do
eg
class Person < ActiveRecord::Base belongs_to :team ... end class Task < ActiveRecord::Base belongs_to :person has_one :team, :through => :person end
Is :required still valid ?
I get this error when using :required => true
ArgumentError: Unknown key: :required. Valid keys are: :class_name, :class, :foreign_key, :validate, :autosave, :remote, :dependent, :primary_key, :inverse_of, :foreign_type, :polymorphic, :touch, :counter_cache
Is :required not a valid key anymore ?
Can't find documention on :find_by option
I found code that had a :find_by option on belongs_to. I’m sure it’s more or less self explanatory, but I couldn’t find it listed anywhere as an option.
My bad, belongs_to was in a controller, not a model.
Why such inconsistency on 'extend' design?
Thanks for the great note! Finally… it took me quite some time to find this page and track down why there is such inconsistency between belongs_to and, say, has_many, proxy extension design. Do you (or anyone knowledgeable here) know the reason behind such design inconsistency? It’s quite annoying (and quite abstraction- and documentation-defeating) that one has to look this deep into the source code to see what’s going on.… Thanks!
I would just use a validation instead of (the probably removed) :required
Just make sure you validate the presence of the association and not the foreign key, otherwise it will not work on new records.
The down side is that it will require the record in the cache, and will make a query otherwise. You can add `unless: :<foreign_key>?` If that’s a problem for you.
Not a one-to-one-relationship
It’s incorrect to state that belongs_to “Specifies a one-to-one association with another class”.
If the inverse association is has_one then the model specifying belongs_to is the LHS of a zero/one-to-one relationship.
If the inverse association is has_many then the model specifying belongs_to is the LHS of a zero/many-to-one relationship.
Unless you know what the inverse association is, all you can assume is that instances of a class specifying a belongs_to association can be related to at most a single instance of the other class.
Careful when updating foreign key directly
Seems when you change key directly it doesn’t update association automatically.
>> chicken = Chicken.first >> chicken.head => old_head >> chicken.head_id = new_head.id >> chicken.head => old_head
Easy (stupid?) way to fix it:
class Chicken def head_id=(value) self.head = Head.find_by_id(value) end end
:autosave => false vs. :autosave => nil
The documentation above mentions that :autosave => true always saves the association and that it’s “off” by default. What it doesn’t mention what they mean by “off”.
-
:autosave => nil (the default “off” behavior) will still autosave the association if it has changed or is a new record.
-
:autosave => false seems to prevent autosaving of the association, even if it has changed.
I’ve found :autosave => false to be useful behavior when trying to prevent cyclical dependency loops; there are likely other useful use cases out there.