guides/source/association_basics.textile in railties-3.2.1 vs guides/source/association_basics.textile in railties-3.2.2.rc1
- old
+ new
@@ -356,10 +356,11 @@
* Controlling caching
* Avoiding name collisions
* Updating the schema
* Controlling association scope
+* Bi-directional associations
h4. Controlling Caching
All of the association methods are built around caching, which keeps the result of the most recent query available for further operations. The cache is even shared across methods. For example:
@@ -499,10 +500,63 @@
end
end
end
</ruby>
+h4. Bi-directional Associations
+
+It's normal for associations to work in two directions, requiring declaration on two different models:
+
+<ruby>
+class Customer < ActiveRecord::Base
+ has_many :orders
+end
+
+class Order < ActiveRecord::Base
+ belongs_to :customer
+end
+</ruby>
+
+By default, Active Record doesn't know about the connection between these associations. This can lead to two copies of an object getting out of sync:
+
+<ruby>
+c = Customer.first
+o = c.orders.first
+c.first_name == o.customer.first_name # => true
+c.first_name = 'Manny'
+c.first_name == o.customer.first_name # => false
+</ruby>
+
+This happens because c and o.customer are two different in-memory representations of the same data, and neither one is automatically refreshed from changes to the other. Active Record provides the +:inverse_of+ option so that you can inform it of these relations:
+
+<ruby>
+class Customer < ActiveRecord::Base
+ has_many :orders, :inverse_of => :customer
+end
+
+class Order < ActiveRecord::Base
+ belongs_to :customer, :inverse_of => :orders
+end
+</ruby>
+
+With these changes, Active Record will only load one copy of the customer object, preventing inconsistencies and making your application more efficient:
+
+<ruby>
+c = Customer.first
+o = c.orders.first
+c.first_name == o.customer.first_name # => true
+c.first_name = 'Manny'
+c.first_name == o.customer.first_name # => true
+</ruby>
+
+There are a few limitations to +inverse_of+ support:
+
+* They do not work with <tt>:through</tt> associations.
+* They do not work with <tt>:polymorphic</tt> associations.
+* They do not work with <tt>:as</tt> associations.
+* For +belongs_to+ associations, +has_many+ inverse associations are ignored.
+
h3. Detailed Association Reference
The following sections give the details of each type of association, including the methods that they add and the options that you can use when declaring an association.
h4. +belongs_to+ Association Reference
@@ -592,10 +646,11 @@
* +:conditions+
* +:counter_cache+
* +:dependent+
* +:foreign_key+
* +:include+
+* +:inverse_of+
* +:polymorphic+
* +:readonly+
* +:select+
* +:touch+
* +:validate+
@@ -718,10 +773,24 @@
end
</ruby>
NOTE: There's no need to use +:include+ for immediate associations - that is, if you have +Order belongs_to :customer+, then the customer is eager-loaded automatically when it's needed.
+h6(#belongs_to-inverse_of). +:inverse_of+
+
+The +:inverse_of+ option specifies the name of the +has_many+ or +has_one+ association that is the inverse of this association. Does not work in combination with the +:polymorphic+ options.
+
+<ruby>
+class Customer < ActiveRecord::Base
+ has_many :orders, :inverse_of => :customer
+end
+
+class Order < ActiveRecord::Base
+ belongs_to :customer, :inverse_of => :orders
+end
+</ruby>
+
h6(#belongs_to-polymorphic). +:polymorphic+
Passing +true+ to the +:polymorphic+ option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail <a href="#polymorphic-associations">earlier in this guide</a>.
h6(#belongs_to-readonly). +:readonly+
@@ -857,10 +926,11 @@
* +:class_name+
* +:conditions+
* +:dependent+
* +:foreign_key+
* +:include+
+* +:inverse_of+
* +:order+
* +:primary_key+
* +:readonly+
* +:select+
* +:source+
@@ -946,10 +1016,24 @@
class Representative < ActiveRecord::Base
has_many :accounts
end
</ruby>
+h6(#has_one-inverse_of). +:inverse_of+
+
+The +:inverse_of+ option specifies the name of the +belongs_to+ association that is the inverse of this association. Does not work in combination with the +:through+ or +:as+ options.
+
+<ruby>
+class Supplier < ActiveRecord::Base
+ has_one :account, :inverse_of => :supplier
+end
+
+class Account < ActiveRecord::Base
+ belongs_to :supplier, :inverse_of => :account
+end
+</ruby>
+
h6(#has_one-order). +:order+
The +:order+ option dictates the order in which associated objects will be received (in the syntax used by an SQL +ORDER BY+ clause). Because a +has_one+ association will only retrieve a single associated object, this option should not be needed.
h6(#has_one-primary_key). +:primary_key+
@@ -1175,10 +1259,11 @@
* +:extend+
* +:finder_sql+
* +:foreign_key+
* +:group+
* +:include+
+* +:inverse_of+
* +:limit+
* +:offset+
* +:order+
* +:primary_key+
* +:readonly+
@@ -1311,9 +1396,23 @@
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :order
+end
+</ruby>
+
+h6(#has_many-inverse_of). +:inverse_of+
+
+The +:inverse_of+ option specifies the name of the +belongs_to+ association that is the inverse of this association. Does not work in combination with the +:through+ or +:as+ options.
+
+<ruby>
+class Customer < ActiveRecord::Base
+ has_many :orders, :inverse_of => :customer
+end
+
+class Order < ActiveRecord::Base
+ belongs_to :customer, :inverse_of => :orders
end
</ruby>
h6(#has_many-limit). +:limit+