diff options
Diffstat (limited to 'activerecord/lib/active_record/associations.rb')
-rwxr-xr-x | activerecord/lib/active_record/associations.rb | 76 |
1 files changed, 71 insertions, 5 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index a0aeff68b6..60da632b3b 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -519,13 +519,13 @@ module ActiveRecord # # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # will result in a single SQL query with joins along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and + # This will result in a single SQL query with joins along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and # <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions like this can have unintended consequences. # In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole # and not just to the association. You must disambiguate column references for this fallback to happen, for example # <tt>:order => "author.name DESC"</tt> will work but <tt>:order => "name DESC"</tt> will not. # - # If you do want eagerload only some members of an association it is usually more natural to <tt>:include</tt> an association + # If you do want eager load only some members of an association it is usually more natural to <tt>:include</tt> an association # which has conditions defined on it: # # class Post < ActiveRecord::Base @@ -534,7 +534,7 @@ module ActiveRecord # # Post.find(:all, :include => :approved_comments) # - # will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved. + # This will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved. # # If you eager load an association with a specified <tt>:limit</tt> option, it will be ignored, returning all the associated objects: # @@ -557,7 +557,7 @@ module ActiveRecord # # Address.find(:all, :include => :addressable) # - # will execute one query to load the addresses and load the addressables with one query per addressable type. + # This will execute one query to load the addresses and load the addressables with one query per addressable type. # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of # addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent @@ -641,6 +641,60 @@ module ActiveRecord # end # end # + # == Bi-directional associations + # + # When you specify an association there is usually an association on the associated model that specifies the same + # relationship in reverse. For example, with the following models: + # + # class Dungeon < ActiveRecord::Base + # has_many :traps + # has_one :evil_wizard + # end + # + # class Trap < ActiveRecord::Base + # belongs_to :dungeon + # end + # + # class EvilWizard < ActiveRecord::Base + # belongs_to :dungeon + # end + # + # The +traps+ association on +Dungeon+ and the the +dungeon+ association on +Trap+ are the inverse of each other and the + # inverse of the +dungeon+ association on +EvilWizard+ is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default, + # +ActiveRecord+ doesn't do know anything about these inverse relationships and so no object loading optimisation is possible. For example: + # + # d = Dungeon.first + # t = d.traps.first + # d.level == t.dungeon.level # => true + # d.level = 10 + # d.level == t.dungeon.level # => false + # + # The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to the same object data from the database, but are + # actually different in-memory copies of that data. Specifying the <tt>:inverse_of</tt> option on associations lets you tell + # +ActiveRecord+ about inverse relationships and it will optimise object loading. For example, if we changed our model definitions to: + # + # class Dungeon < ActiveRecord::Base + # has_many :traps, :inverse_of => :dungeon + # has_one :evil_wizard, :inverse_of => :dungeon + # end + # + # class Trap < ActiveRecord::Base + # belongs_to :dungeon, :inverse_of => :traps + # end + # + # class EvilWizard < ActiveRecord::Base + # belongs_to :dungeon, :inverse_of => :evil_wizard + # end + # + # Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same in-memory instance and our final <tt>d.level == t.dungeon.level</tt> + # will return +true+. + # + # There are limitations to <tt>:inverse_of</tt> support: + # + # * does not work with <tt>:through</tt> associations. + # * does not work with <tt>:polymorphic</tt> associations. + # * for +belongs_to+ associations +has_many+ inverse associations are ignored. + # # == Type safety with <tt>ActiveRecord::AssociationTypeMismatch</tt> # # If you attempt to assign an object to an association that doesn't match the inferred or specified <tt>:class_name</tt>, you'll @@ -781,6 +835,10 @@ module ActiveRecord # If false, don't validate the associated objects when saving the parent object. true by default. # [:autosave] # If true, always save any loaded members and destroy members marked for destruction, when saving the parent object. Off by default. + # [:inverse_of] + # Specifies the name of the <tt>belongs_to</tt> association on the associated object that is the inverse of this <tt>has_many</tt> + # association. Does not work in combination with <tt>:through</tt> or <tt>:as</tt> options. + # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional assocations for more detail. # # Option examples: # has_many :comments, :order => "posted_on" @@ -890,6 +948,10 @@ module ActiveRecord # If false, don't validate the associated object when saving the parent object. +false+ by default. # [:autosave] # If true, always save the associated object or destroy it if marked for destruction, when saving the parent object. Off by default. + # [:inverse_of] + # Specifies the name of the <tt>belongs_to</tt> association on the associated object that is the inverse of this <tt>has_one</tt> + # association. Does not work in combination with <tt>:through</tt> or <tt>:as</tt> options. + # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional assocations for more detail. # # Option examples: # has_one :credit_card, :dependent => :destroy # destroys the associated credit card @@ -992,6 +1054,10 @@ module ActiveRecord # [:touch] # If true, the associated object will be touched (the updated_at/on attributes set to now) when this record is either saved or # destroyed. If you specify a symbol, that attribute will be updated with the current time instead of the updated_at/on attribute. + # [:inverse_of] + # Specifies the name of the <tt>has_one</tt> or <tt>has_many</tt> association on the associated object that is the inverse of this <tt>belongs_to</tt> + # association. Does not work in combination with the <tt>:polymorphic</tt> options. + # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional assocations for more detail. # # Option examples: # belongs_to :firm, :foreign_key => "client_of" @@ -1201,7 +1267,7 @@ module ActiveRecord private # Generates a join table name from two provided table names. - # The names in the join table namesme end up in lexicographic order. + # The names in the join table names end up in lexicographic order. # # join_table_name("members", "clubs") # => "clubs_members" # join_table_name("members", "special_clubs") # => "members_special_clubs" |