Ticket #8899: doc_grammar_fixes_for_associations3.2.diff
| File doc_grammar_fixes_for_associations3.2.diff, 70.6 kB (added by seanhussey, 1 year ago) |
|---|
-
activerecord/lib/active_record/callbacks.rb
old new 1 1 require 'observer' 2 2 3 3 module ActiveRecord 4 # Callbacks are hooks into the lifecycle of an Active Record object that allow syou to trigger logic4 # Callbacks are hooks into the lifecycle of an Active Record object that allow you to trigger logic 5 5 # before or after an alteration of the object state. This can be used to make sure that associated and 6 # dependent objects are deleted when destroy is called (by overwriting before_destroy) or to massage attributes7 # before they're validated (by overwriting before_validation). As an example of the callbacks initiated, consider8 # the Base#savecall:6 # dependent objects are deleted when destroy is called (by overwriting +before_destroy+) or to massage attributes 7 # before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider 8 # the <tt>Base#save</tt> call: 9 9 # 10 # * (-) save11 # * (-) valid?12 # * (1) before_validation13 # * (2) before_validation_on_create14 # * (-) validate15 # * (-) validate_on_create16 # * (3) after_validation17 # * (4) after_validation_on_create18 # * (5) before_save19 # * (6) before_create20 # * (-) create21 # * (7) after_create22 # * (8) after_save10 # * (-) <tt>save</tt> 11 # * (-) <tt>valid</tt> 12 # * (1) <tt>before_validation</tt> 13 # * (2) <tt>before_validation_on_create</tt> 14 # * (-) <tt>validate</tt> 15 # * (-) <tt>validate_on_create</tt> 16 # * (3) <tt>after_validation</tt> 17 # * (4) <tt>after_validation_on_create</tt> 18 # * (5) <tt>before_save</tt> 19 # * (6) <tt>before_create</tt> 20 # * (-) <tt>create</tt> 21 # * (7) <tt>after_create</tt> 22 # * (8) <tt>after_save</tt> 23 23 # 24 24 # That's a total of eight callbacks, which gives you immense power to react and prepare for each state in the 25 25 # Active Record lifecycle. … … 62 62 # before_destroy :destroy_readers 63 63 # end 64 64 # 65 # Now, when Topic#destroy is run only +destroy_author+ is called. When Reply#destroy is runboth +destroy_author+ and66 # +destroy_readers+ iscalled. Contrast this to the situation where we've implemented the save behavior through overwriteable65 # Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is run, both +destroy_author+ and 66 # +destroy_readers+ are called. Contrast this to the situation where we've implemented the save behavior through overwriteable 67 67 # methods: 68 68 # 69 69 # class Topic < ActiveRecord::Base … … 74 74 # def before_destroy() destroy_readers end 75 75 # end 76 76 # 77 # In that case, Reply#destroy would only run +destroy_readers+ and _not_ +destroy_author+. Souse the callback macros when78 # you want to ensure that a certain callback is called for the entire hierarchy and the regular overwriteable methods when you79 # w ant to leave it up to each descendent to decide whether they want to call +super+ and trigger the inherited callbacks.77 # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+. So, use the callback macros when 78 # you want to ensure that a certain callback is called for the entire hierarchy, and use the regular overwriteable methods 79 # when you want to leave it up to each descendent to decide whether they want to call +super+ and trigger the inherited callbacks. 80 80 # 81 81 # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the callbacks before specifying the 82 82 # associations. Otherwise, you might trigger the loading of a child before the parent has registered the callbacks and they won't … … 143 143 # before_destroy 'self.class.delete_all "parent_id = #{id}"' 144 144 # end 145 145 # 146 # Notice that single plings (') are used so the #{id}part isn't evaluated until the callback is triggered. Also note that these146 # Notice that single plings (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback is triggered. Also note that these 147 147 # inline callbacks can be stacked just like the regular ones: 148 148 # 149 149 # class Topic < ActiveRecord::Base … … 151 151 # 'puts "Evaluated after parents are destroyed"' 152 152 # end 153 153 # 154 # == The after_find and after_initializeexceptions154 # == The +after_find+ and +after_initialize+ exceptions 155 155 # 156 # Because after_find and after_initialize are called for each object found and instantiated by a finder, such as Base.find(:all), we've had157 # to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, after_findand158 # after_initializewill only be run if an explicit implementation is defined (<tt>def after_find</tt>). In that case, all of the156 # Because +after_find+ and +after_initialize+ are called for each object found and instantiated by a finder, such as <tt>Base.find(:all)</tt>, we've had 157 # to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, +after_find+ and 158 # +after_initialize+ will only be run if an explicit implementation is defined (<tt>def after_find</tt>). In that case, all of the 159 159 # callback types will be called. 160 160 # 161 # == before_validation*returning statements161 # == <tt>before_validation*</tt> returning statements 162 162 # 163 # If the returning value of a before_validation callback can be evaluated to false, the process will be aborted and Base#save will return false.164 # If Base#save! is called it will raise a RecordNotSave error.163 # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be aborted and <tt>Base#save</tt> will return +false+. 164 # If <tt>Base#save!</tt> is called it will raise a +RecordNotSave+ exception. 165 165 # Nothing will be appended to the errors object. 166 166 # 167 167 # == Cancelling callbacks 168 168 # 169 # If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_*callback returns170 # false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks169 # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are cancelled. If an <tt>after_*</tt> callback returns 170 # +false+, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks 171 171 # defined as methods on the model, which are called last. 172 172 module Callbacks 173 173 CALLBACKS = %w( … … 215 215 end 216 216 end 217 217 218 # Is called when the object was instantiated by one of the finders, like Base.find.218 # Is called when the object was instantiated by one of the finders, like <tt>Base.find</tt>. 219 219 #def after_find() end 220 220 221 # Is called after the object has been instantiated by a call to Base.new.221 # Is called after the object has been instantiated by a call to <tt>Base.new</tt>. 222 222 #def after_initialize() end 223 223 224 224 def initialize_with_callbacks(attributes = nil) #:nodoc: … … 229 229 end 230 230 private :initialize_with_callbacks 231 231 232 # Is called _before_ Base.save (regardless of whether it's a create or updatesave).232 # Is called _before_ <tt>Base.save</tt> (regardless of whether it's a +create+ or +update+ save). 233 233 def before_save() end 234 234 235 # Is called _after_ Base.save (regardless of whether it's a create or updatesave).235 # Is called _after_ <tt>Base.save</tt> (regardless of whether it's a +create+ or +update+ save). 236 236 # 237 237 # class Contact < ActiveRecord::Base 238 238 # after_save { logger.info( 'New contact saved!' ) } … … 246 246 end 247 247 private :create_or_update_with_callbacks 248 248 249 # Is called _before_ Base.saveon new objects that haven't been saved yet (no record exists).249 # Is called _before_ <tt>Base.save</tt> on new objects that haven't been saved yet (no record exists). 250 250 def before_create() end 251 251 252 # Is called _after_ Base.saveon new objects that haven't been saved yet (no record exists).252 # Is called _after_ <tt>Base.save</tt> on new objects that haven't been saved yet (no record exists). 253 253 def after_create() end 254 254 def create_with_callbacks #:nodoc: 255 255 return false if callback(:before_create) == false … … 259 259 end 260 260 private :create_with_callbacks 261 261 262 # Is called _before_ Base.saveon existing objects that have a record.262 # Is called _before_ <tt>Base.save</tt> on existing objects that have a record. 263 263 def before_update() end 264 264 265 # Is called _after_ Base.saveon existing objects that have a record.265 # Is called _after_ <tt>Base.save</tt> on existing objects that have a record. 266 266 def after_update() end 267 267 268 268 def update_with_callbacks #:nodoc: … … 273 273 end 274 274 private :update_with_callbacks 275 275 276 # Is called _before_ Validations.validate (which is part of the Base.savecall).276 # Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call). 277 277 def before_validation() end 278 278 279 # Is called _after_ Validations.validate (which is part of the Base.savecall).279 # Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call). 280 280 def after_validation() end 281 281 282 # Is called _before_ Validations.validate (which is part of the Base.savecall) on new objects282 # Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on new objects 283 283 # that haven't been saved yet (no record exists). 284 284 def before_validation_on_create() end 285 285 286 # Is called _after_ Validations.validate (which is part of the Base.savecall) on new objects286 # Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on new objects 287 287 # that haven't been saved yet (no record exists). 288 288 def after_validation_on_create() end 289 289 290 # Is called _before_ Validations.validate (which is part of the Base.savecall) on290 # Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on 291 291 # existing objects that have a record. 292 292 def before_validation_on_update() end 293 293 294 # Is called _after_ Validations.validate (which is part of the Base.savecall) on294 # Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on 295 295 # existing objects that have a record. 296 296 def after_validation_on_update() end 297 297 … … 308 308 return result 309 309 end 310 310 311 # Is called _before_ Base.destroy.311 # Is called _before_ <tt>Base.destroy</tt>. 312 312 # 313 313 # Note: If you need to _destroy_ or _nullify_ associated records first, 314 # use the _:dependent_option on your associations.314 # use the <tt>:dependent</tt> option on your associations. 315 315 def before_destroy() end 316 316 317 # Is called _after_ Base.destroy(and all the attributes have been frozen).317 # Is called _after_ <tt>Base.destroy</tt> (and all the attributes have been frozen). 318 318 # 319 319 # class Contact < ActiveRecord::Base 320 320 # after_destroy { |record| logger.info( "Contact #{record.id} was destroyed." ) } -
activerecord/lib/active_record/associations/association_proxy.rb
old new 139 139 end 140 140 141 141 # Can be overwritten by associations that might have the foreign key available for an association without 142 # having the object itself (and still being a new record). Currently, only belongs_to present this scenario.142 # having the object itself (and still being a new record). Currently, only belongs_to presents this scenario. 143 143 def foreign_key_present 144 144 false 145 145 end -
activerecord/lib/active_record/associations/association_collection.rb
old new 65 65 66 66 # Removes all records from this association. Returns +self+ so method calls may be chained. 67 67 def clear 68 return self if length.zero? # forces load_target if hasn't happened already68 return self if length.zero? # forces load_target if it hasn't happened already 69 69 70 70 if @reflection.options[:dependent] && @reflection.options[:dependent] == :delete_all 71 71 destroy_all -
activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
old new 14 14 end 15 15 16 16 def create(attributes = {}) 17 # Can't use Base.create since the foreign key may be a protected attribute.17 # Can't use Base.create because the foreign key may be a protected attribute. 18 18 if attributes.is_a?(Array) 19 19 attributes.collect { |attr| create(attr) } 20 20 else … … 137 137 end 138 138 139 139 # Join tables with additional columns on top of the two foreign keys must be considered ambigious unless a select 140 # clause has been explicitly defined. Otherwise you can get broken records back, if, say, the join column also has141 # an d id column, whichwill then overwrite the id column of the records coming back.140 # clause has been explicitly defined. Otherwise you can get broken records back, if, for example, the join column also has 141 # an id column. This will then overwrite the id column of the records coming back. 142 142 def finding_with_ambigious_select?(select_clause) 143 143 !select_clause && @owner.connection.columns(@reflection.options[:join_table], "Join Table Columns").size != 2 144 144 end -
activerecord/lib/active_record/associations/has_one_association.rb
old new 76 76 end 77 77 78 78 def new_record(replace_existing) 79 # make sure we load the target first, if we plan on replacing the existing79 # Make sure we load the target first, if we plan on replacing the existing 80 80 # instance. Otherwise, if the target has not previously been loaded 81 81 # elsewhere, the instance we create will get orphaned. 82 82 load_target if replace_existing -
activerecord/lib/active_record/associations/has_many_through_association.rb
old new 67 67 68 68 [:push, :concat].each { |method| alias_method method, :<< } 69 69 70 # Remove +records+ from this association. Does not destroy +records+.70 # Removes +records+ from this association. Does not destroy +records+. 71 71 def delete(*records) 72 72 records = flatten_deeper(records) 73 73 records.each { |associate| raise_on_type_mismatch(associate) } -
activerecord/lib/active_record/associations.rb
old new 76 76 77 77 # Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like 78 78 # "Project has one Project Manager" or "Project belongs to a Portfolio". Each macro adds a number of methods to the class which are 79 # specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby's own attr*79 # specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby's own <tt>attr*</tt> 80 80 # methods. Example: 81 81 # 82 82 # class Project < ActiveRecord::Base … … 146 146 # 147 147 # ActiveRecord associations can be used to describe relations with one-to-one, one-to-many 148 148 # and many-to-many cardinality. Each model uses an association to describe its role in 149 # the relation. In each case, the belongs_toassociation is used in the model that has149 # the relation. In each case, the +belongs_to+ association is used in the model that has 150 150 # the foreign key. 151 151 # 152 152 # === One-to-one 153 153 # 154 # Use has_one in the base, and belongs_toin the associated model.154 # Use +has_one+ in the base, and +belongs_to+ in the associated model. 155 155 # 156 156 # class Employee < ActiveRecord::Base 157 157 # has_one :office … … 162 162 # 163 163 # === One-to-many 164 164 # 165 # Use has_many in the base, and belongs_toin the associated model.165 # Use +has_many+ in the base, and +belongs_to+ in the associated model. 166 166 # 167 167 # class Manager < ActiveRecord::Base 168 168 # has_many :employees … … 175 175 # 176 176 # There are two ways to build a many-to-many relationship. 177 177 # 178 # The first way uses a has_many association with the :throughoption and a join model, so178 # The first way uses a +has_many+ association with the <tt>:through</tt> option and a join model, so 179 179 # there are two stages of associations. 180 180 # 181 181 # class Assignment < ActiveRecord::Base … … 191 191 # has_many :programmers, :through => :assignments 192 192 # end 193 193 # 194 # For the second way, use has_and_belongs_to_manyin both models. This requires a join table194 # For the second way, use +has_and_belongs_to_many+ in both models. This requires a join table 195 195 # that has no corresponding model or primary key. 196 196 # 197 197 # class Programmer < ActiveRecord::Base … … 201 201 # has_and_belongs_to_many :programmers # foreign keys in the join table 202 202 # end 203 203 # 204 # It is not always a simple decision which way of building a many-to-many relationship is best.205 # But if you need to work with the relationship model as its own entity, then you'll need to206 # use has_many :through. Use has_and_belongs_to_manywhen working with legacy schemas or when204 # Choosing which way to build a many-to-many relationship is not always simple. 205 # If you need to work with the relationship model as its own entity, 206 # use <tt>has_many :through</tt>. Use +has_and_belongs_to_many+ when working with legacy schemas or when 207 207 # you never work directly with the relationship itself. 208 208 # 209 # == Is it a belongs_to or has_oneassociation?209 # == Is it a +belongs_to+ or +has_one+ association? 210 210 # 211 # Both express a 1-1 relationship , the difference is mostly where to place the foreign key, which goes on the table for the class212 # saying belongs_to. Example:211 # Both express a 1-1 relationship. The difference is mostly where to place the foreign key, which goes on the table for the class 212 # declaring the +belongs_to+ relationship. Example: 213 213 # 214 214 # class User < ActiveRecord::Base 215 215 # # I reference an account. … … 243 243 # 244 244 # === One-to-one associations 245 245 # 246 # * Assigning an object to a has_oneassociation automatically saves that object and the object being replaced (if there is one), in247 # order to update their primary keys - except if the parent object is unsaved ( new_record? == true).248 # * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns falseand the assignment246 # * Assigning an object to a +has_one+ association automatically saves that object and the object being replaced (if there is one), in 247 # order to update their primary keys - except if the parent object is unsaved (<tt>new_record? == true</tt>). 248 # * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns +false+ and the assignment 249 249 # is cancelled. 250 # * If you wish to assign an object to a has_one association without saving it, use the #association.buildmethod (documented below).251 # * Assigning an object to a belongs_to association does not save the object, since the foreign key field belongs on the parent. It does252 # not save the parent either.250 # * If you wish to assign an object to a +has_one+ association without saving it, use the <tt>#association.build</tt> method (documented below). 251 # * Assigning an object to a +belongs_to+ association does not save the object, since the foreign key field belongs on the parent. It 252 # does not save the parent either. 253 253 # 254 254 # === Collections 255 255 # 256 # * Adding an object to a collection ( has_many or has_and_belongs_to_many) automatically saves that object, except if the parent object256 # * Adding an object to a collection (+has_many+ or +has_and_belongs_to_many+) automatically saves that object, except if the parent object 257 257 # (the owner of the collection) is not yet stored in the database. 258 # * If saving any of the objects being added to a collection (via #push or similar) fails, then #push returns false.259 # * You can add an object to a collection without automatically saving it by using the #collection.buildmethod (documented below).260 # * All unsaved ( new_record? == true) members of the collection are automatically saved when the parent is saved.258 # * If saving any of the objects being added to a collection (via <tt>#push</tt> or similar) fails, then <tt>#push</tt> returns +false+. 259 # * You can add an object to a collection without automatically saving it by using the <tt>#collection.build</tt> method (documented below). 260 # * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically saved when the parent is saved. 261 261 # 262 262 # === Association callbacks 263 263 # 264 264 # Similiar to the normal callbacks that hook into the lifecycle of an Active Record object, you can also define callbacks that get 265 # trigged when you add an object to or remov ing an object from aassociation collection. Example:265 # trigged when you add an object to or remove an object from an association collection. Example: 266 266 # 267 267 # class Project 268 268 # has_and_belongs_to_many :developers, :after_add => :evaluate_velocity … … 278 278 # has_and_belongs_to_many :developers, :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}] 279 279 # end 280 280 # 281 # Possible callbacks are: before_add, after_add, before_remove and after_remove.281 # Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+. 282 282 # 283 # Should any of the before_addcallbacks throw an exception, the object does not get added to the collection. Same with284 # the before_remove callbacks,if an exception is thrown the object doesn't get removed.283 # Should any of the +before_add+ callbacks throw an exception, the object does not get added to the collection. Same with 284 # the +before_remove+ callbacks; if an exception is thrown the object doesn't get removed. 285 285 # 286 286 # === Association extensions 287 287 # 288 # The proxy objects that control sthe access to associations can be extended through anonymous modules. This is especially288 # The proxy objects that control the access to associations can be extended through anonymous modules. This is especially 289 289 # beneficial for adding new finders, creators, and other factory-type methods that are only used as part of this association. 290 290 # Example: 291 291 # … … 319 319 # has_many :people, :extend => FindOrCreateByNameExtension 320 320 # end 321 321 # 322 # If you need to use multiple named extension modules, you can specify an array of modules with the :extendoption.322 # If you need to use multiple named extension modules, you can specify an array of modules with the <tt>:extend</tt> option. 323 323 # In the case of name conflicts between methods in the modules, methods in modules later in the array supercede 324 324 # those earlier in the array. Example: 325 325 # … … 332 332 # 333 333 # * +proxy_owner+ - Returns the object the association is part of. 334 334 # * +proxy_reflection+ - Returns the reflection object that describes the association. 335 # * +proxy_target+ - Returns the associated object for belongs_to and has_one, or the collection of associated objects for has_many and has_and_belongs_to_many.335 # * +proxy_target+ - Returns the associated object for +belongs_to+ and +has_one+, or the collection of associated objects for +has_many+ and +has_and_belongs_to_many+. 336 336 # 337 337 # === Association Join Models 338 338 # 339 # Has Many associations can be configured with the :throughoption to use an explicit join model to retrieve the data. This340 # operates similarly to a <tt>has_and_belongs_to_many</tt>association. The advantage is that you're able to add validations,339 # Has Many associations can be configured with the <tt>:through</tt> option to use an explicit join model to retrieve the data. This 340 # operates similarly to a +has_and_belongs_to_many+ association. The advantage is that you're able to add validations, 341 341 # callbacks, and extra attributes on the join model. Consider the following schema: 342 342 # 343 343 # class Author < ActiveRecord::Base … … 354 354 # @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to. 355 355 # @author.books # selects all books by using the Authorship join model 356 356 # 357 # You can also go through a has_manyassociation on the join model:357 # You can also go through a +has_many+ association on the join model: 358 358 # 359 359 # class Firm < ActiveRecord::Base 360 360 # has_many :clients … … 377 377 # === Polymorphic Associations 378 378 # 379 379 # Polymorphic associations on models are not restricted on what types of models they can be associated with. Rather, they 380 # specify an interface that a has_manyassociation must adhere to.380 # specify an interface that a +has_many+ association must adhere to. 381 381 # 382 382 # class Asset < ActiveRecord::Base 383 383 # belongs_to :attachable, :polymorphic => true 384 384 # end 385 385 # 386 386 # class Post < ActiveRecord::Base 387 # has_many :assets, :as => :attachable # The <tt>:as</tt>option specifies the polymorphic interface to use.387 # has_many :assets, :as => :attachable # The :as option specifies the polymorphic interface to use. 388 388 # end 389 389 # 390 390 # @asset.attachable = @post 391 391 # 392 392 # This works by using a type column in addition to a foreign key to specify the associated record. In the Asset example, you'd need 393 # an attachable_id integer column and an attachable_typestring column.393 # an +attachable_id+ integer column and an +attachable_type+ string column. 394 394 # 395 395 # Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order 396 396 # for the associations to work as expected, ensure that you store the base model for the STI models in the 397 397 # type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts 398 # and member posts that use the posts table for STI. So there will be an additional 'type'column in the posts table.398 # and member posts that use the posts table for STI. In this case, there must be a +type+ column in the posts table. 399 399 # 400 400 # class Asset < ActiveRecord::Base 401 401 # belongs_to :attachable, :polymorphic => true … … 431 431 # == Eager loading of associations 432 432 # 433 433 # Eager loading is a way to find objects of a certain class and a number of named associations along with it in a single SQL call. This is 434 # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need sto display their author434 # one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to display their author 435 435 # triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example: 436 436 # 437 437 # class Post < ActiveRecord::Base … … 451 451 # 452 452 # for post in Post.find(:all, :include => :author) 453 453 # 454 # This references the name of the belongs_to association that also used the :authorsymbol, so the find will now weave in a join something455 # like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101.454 # This references the name of the +belongs_to+ association that also used the <tt>:author</tt> symbol, so the find will now weave in a join something 455 # like this: <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Doing so will cut down the number of queries from 201 to 101. 456 456 # 457 457 # We can improve upon the situation further by referencing both associations in the finder with: 458 458 # 459 459 # for post in Post.find(:all, :include => [ :author, :comments ]) 460 460 # 461 # That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query.461 # That'll add another join along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt>. And we'll be down to 1 query. 462 462 # 463 # To include a deep hierarchy of associations, us inga hash:463 # To include a deep hierarchy of associations, use a hash: 464 464 # 465 465 # for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ]) 466 466 # … … 472 472 # catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above. 473 473 # 474 474 # Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So 475 # :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the SELECTstatement too, the476 # :selectoption is ignored.475 # <tt>:order => "posts.id DESC"</tt> will work while <tt>:order => "id DESC"</tt> will not. Because eager loading generates the +SELECT+ statement too, the 476 # <tt>:select</tt> option is ignored. 477 477 # 478 478 # You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions 479 479 # as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich 480 # associations" with has_and_belongs_to_manyare not a good fit for eager loading.480 # associations" with +has_and_belongs_to_many+ are not a good fit for eager loading. 481 481 # 482 482 # When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated 483 483 # before the actual model exists. … … 485 485 # == Table Aliasing 486 486 # 487 487 # ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once, 488 # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended488 # the standard table name is used. The second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>. Indexes are appended 489 489 # for any more successive uses of the table name. 490 490 # 491 491 # Post.find :all, :include => :comments … … 505 505 # TreeMixin.find :all, :include => {:children => {:parent => :children}} 506 506 # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ... 507 507 # LEFT OUTER JOIN parents_mixins ... 508 # LEFT OUTER JOIN mixins childrens_mixins_2508 # LEFT OUTER JOIN mixins childrens_mixins_2 509 509 # 510 # Has and Belongs to Many join tables use the same idea, but add a _joinsuffix:510 # Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix: 511 511 # 512 512 # Post.find :all, :include => :categories 513 513 # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ... … … 519 519 # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories 520 520 # LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts 521 521 # 522 # If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations..522 # If you wish to specify your own custom joins using a <tt>:joins</tt> option, those table names will take precedence over the eager associations: 523 523 # 524 524 # Post.find :all, :include => :comments, :joins => "inner join comments ..." 525 525 # # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ... … … 544 544 # end 545 545 # end 546 546 # 547 # When Firm#clients is called, it'll in turn call <tt>MyApplication::Business::Company.find(firm.id)</tt>. If you want to associate548 # with a class in another module scope this can be done by specifying the complete class name, such as:547 # When <tt>Firm#clients</tt> is called, it will in turn call <tt>MyApplication::Business::Company.find(firm.id)</tt>. If you want to associate 548 # with a class in another module scope, this can be done by specifying the complete class name. Example: 549 549 # 550 550 # module MyApplication 551 551 # module Business … … 559 559 # end 560 560 # end 561 561 # 562 # == Type safety with ActiveRecord::AssociationTypeMismatch562 # == Type safety with <tt>ActiveRecord::AssociationTypeMismatch</tt> 563 563 # 564 564 # If you attempt to assign an object to an association that doesn't match the inferred or specified <tt>:class_name</tt>, you'll 565 # get a ActiveRecord::AssociationTypeMismatch.565 # get an <tt>ActiveRecord::AssociationTypeMismatch</tt>. 566 566 # 567 567 # == Options 568 568 # 569 # All of the association macros can be specialized through options which makes more complex casesthan the simple and guessable ones569 # All of the association macros can be specialized through options. This makes cases more complex than the simple and guessable ones 570 570 # possible. 571 571 module ClassMethods 572 # Adds the following methods for retrieval and query of collections of associated objects .572 # Adds the following methods for retrieval and query of collections of associated objects: 573 573 # +collection+ is replaced with the symbol passed as the first argument, so 574 574 # <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>. 575 575 # * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects. 576 576 # An empty array is returned if none are found. 577 577 # * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by setting their foreign keys to the collection's primary key. 578 578 # * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL. 579 # This will also destroy the objects if they're declared as belongs_toand dependent on this model.579 # This will also destroy the objects if they're declared as +belongs_to+ and dependent on this model. 580 580 # * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate. 581 # * <tt>collection_singular_ids</tt> - returns an array of the associated objects ids581 # * <tt>collection_singular_ids</tt> - returns an array of the associated objects' ids 582 582 # * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+ 583 583 # * <tt>collection.clear</tt> - removes every object from the collection. This destroys the associated objects if they 584 584 # are associated with <tt>:dependent => :destroy</tt>, deletes them directly from the database if <tt>:dependent => :delete_all</tt>, 585 # and sets their foreign keys to NULL otherwise.586 # * <tt>collection.empty?</tt> - returns trueif there are no associated objects.585 # or otherwise sets their foreign keys to NULL. 586 # * <tt>collection.empty?</tt> - returns +true+ if there are no associated objects. 587 587 # * <tt>collection.size</tt> - returns the number of associated objects. 588 588 # * <tt>collection.find</tt> - finds an associated object according to the same rules as Base.find. 589 589 # * <tt>collection.build(attributes = {}, ...)</tt> - returns one or more new objects of the collection type that have been instantiated 590 # with +attributes+ and linked to this object through a foreign key but have not yet been saved. *Note:* This only works if an591 # associated object already exists, not if it's nil!590 # with +attributes+ and linked to this object through a foreign key, but have not yet been saved. *Note:* This only works if an 591 # associated object already exists, not if it's +nil+! 592 592 # * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated 593 # with +attributes+ and linked to this object through a foreign keyand that has already been saved (if it passed the validation).594 # *Note:* This only works if an associated object already exists, not if it's nil!593 # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation). 594 # *Note:* This only works if an associated object already exists, not if it's +nil+! 595 595 # 596 # Example: A Firmclass declares <tt>has_many :clients</tt>, which will add:596 # Example: A +Firm+ class declares <tt>has_many :clients</tt>, which will add: 597 597 # * <tt>Firm#clients</tt> (similar to <tt>Clients.find :all, :conditions => "firm_id = #{id}"</tt>) 598 598 # * <tt>Firm#clients<<</tt> 599 599 # * <tt>Firm#clients.delete</tt> … … 612 612 # * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred 613 613 # from the association name. So <tt>has_many :products</tt> will by default be linked to the +Product+ class, but 614 614 # if the real class name is +SpecialProduct+, you'll have to specify it with this option. 615 # * <tt>:conditions</tt> - specify the conditions that the associated objects must meet in order to be included as a "WHERE"616 # sql fragment, such as "price > 5 AND name LIKE 'B%'".617 # * <tt>:order</tt> - specify the order in which the associated objects are returned as a "ORDER BY" sqlfragment,618 # such as "last_name, first_name DESC"619 # * <tt>:group</tt> - specify the attribute by which the associated objects are returned as a "GROUP BY" sqlfragment,620 # such as "category"615 # * <tt>:conditions</tt> - specify the conditions that the associated objects must meet in order to be included as a +WHERE+ 616 # SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. 617 # * <tt>:order</tt> - specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment, 618 # such as <tt>last_name, first_name DESC</tt> 619 # * <tt>:group</tt> - specify the attribute by which the associated objects are returned as a <tt>GROUP BY</tt> SQL fragment, 620 # such as +category+ 621 621 # * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name 622 # of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_many association will use "person_id"623 # as the default foreign_key.624 # * <tt>:dependent</tt> - if set to :destroyall the associated objects are destroyed625 # alongside this object by calling their destroy method. If set to :delete_allall associated626 # objects are deleted *without* calling their destroy method. If set to :nullifyall associated627 # objects' foreign keys are set to NULL*without* calling their save callbacks.628 # NOTE: :dependent => true is deprecated and has been replaced with :dependent => :destroy.629 # May not be set if :exclusively_dependentis also set.630 # * <tt>:exclusively_dependent</tt> - Deprecated; equivalent to :dependent => :delete_all. If set to trueall631 # the associated object are deleted in one SQL statement without having their632 # before_destroycallback run. This should only be used on associations that depend solely on this class and don't need to do any633 # clean-up in before_destroy. The upside is that it's much faster, especially if there's a counter_cacheinvolved.634 # May not be set if :dependentis also set.622 # of this class in lower-case and +_id+ suffixed. So a +Person+ class that makes a +has_many+ association will use +person_id+ 623 # as the default +foreign_key+. 624 # * <tt>:dependent</tt> - if set to <tt>:destroy</tt> all the associated objects are destroyed 625 # alongside this object by calling their destroy method. If set to <tt>:delete_all</tt> all associated 626 # objects are deleted *without* calling their destroy method. If set to <tt>:nullify</tt> all associated 627 # objects' foreign keys are set to +NULL+ *without* calling their save callbacks. 628 # NOTE: <tt>:dependent => true</tt> is deprecated and has been replaced with <tt>:dependent => :destroy</tt>. 629 # May not be set if <tt>:exclusively_dependent</tt> is also set. 630 # * <tt>:exclusively_dependent</tt> - Deprecated; equivalent to <tt>:dependent => :delete_all</tt>. If set to +true+ all 631 # the associated objects are deleted in one SQL statement without having their 632 # +before_destroy+ callback run. This should only be used on associations that depend solely on this class and don't need to do any 633 # clean-up in +before_destroy+. The upside is that it's much faster, especially if there's a +counter_cache+ involved. 634 # May not be set if <tt>:dependent</tt> is also set. 635 635 # * <tt>:finder_sql</tt> - specify a complete SQL statement to fetch the association. This is a good way to go for complex 636 636 # associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added. 637 # * <tt>:counter_sql</tt> - specify a complete SQL statement to fetch the size of the association. If +:finder_sql+is638 # specified but +:counter_sql+, +:counter_sql+ will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM.639 # * <tt>:extend</tt> - specify a named module for extending the proxy , see "Association extensions".637 # * <tt>:counter_sql</tt> - specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is 638 # specified but <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>. 639 # * <tt>:extend</tt> - specify a named module for extending the proxy. See "Association extensions". 640 640 # * <tt>:include</tt> - specify second-order associations that should be eager loaded when the collection is loaded. 641 # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BYSQL-clause.641 # * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause. 642 642 # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned. 643 643 # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. 644 # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you for example want to do a join, but not645 # include the joined columns.646 # * <tt>:as</tt>: Specifies a polymorphic interface (See #belongs_to).647 # * <tt>:through</tt>: Specifies a Join Model t o perform the query through. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>644 # * <tt>:select</tt>: By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if you for example want to do a join, 645 # but not include the joined columns. 646 # * <tt>:as</tt>: Specifies a polymorphic interface (See <tt>#belongs_to</tt>). 647 # * <tt>:through</tt>: Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt> 648 648 # are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a <tt>belongs_to</tt> 649 649 # or <tt>has_many</tt> association on the join model. 650 650 # * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be 651 # inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+or652 # +:subscriber+ on +Subscription+, unless a +:source+is given.653 # * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source association654 # is a polymorphic belongs_to.655 # * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through.651 # inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either <tt>:subscribers</tt> or 652 # <tt>:subscriber</tt> on +Subscription+, unless a <tt>:source</tt> is given. 653 # * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source 654 # association is a polymorphic +belongs_to+. 655 # * <tt>:uniq</tt> - if set to +true+, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>. 656 656 # 657 657 # Option examples: 658 658 # has_many :comments, :order => "posted_on" … … 684 684 add_deprecated_api_for_has_many(reflection.name) 685 685 end 686 686 687 # Adds the following methods for retrieval and query of a single associated object .687 # Adds the following methods for retrieval and query of a single associated object: 688 688 # +association+ is replaced with the symbol passed as the first argument, so 689 689 # <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>. 690 # * <tt>association(force_reload = false)</tt> - returns the associated object. Nilis returned if none is found.690 # * <tt>association(force_reload = false)</tt> - returns the associated object. +nil+ is returned if none is found. 691 691 # * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, sets it as the foreign key, 692 692 # and saves the associate object. 693 # * <tt>association.nil?</tt> - returns trueif there is no associated object.693 # * <tt>association.nil?</tt> - returns +true+ if there is no associated object. 694 694 # * <tt>build_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated 695 # with +attributes+ and linked to this object through a foreign key but has not yet been saved. Note: This ONLY works if696 # an association already exists. It will NOT work if the association is nil.695 # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. Note: This ONLY works if 696 # an association already exists. It will NOT work if the association is +nil+. 697 697 # * <tt>create_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated 698 # with +attributes+ and linked to this object through a foreign keyand that has already been saved (if it passed the validation).698 # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation). 699 699 # 700 700 # Example: An Account class declares <tt>has_one :beneficiary</tt>, which will add: 701 701 # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.find(:first, :conditions => "account_id = #{id}")</tt>) … … 710 710 # * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred 711 711 # from the association name. So <tt>has_one :manager</tt> will by default be linked to the +Manager+ class, but 712 712 # if the real class name is +Person+, you'll have to specify it with this option. 713 # * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"714 # sql fragment, such as "rank = 5".713 # * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a +WHERE+ 714 # SQL fragment, such as <tt>rank = 5</tt>. 715 715 # * <tt>:order</tt> - specify the order from which the associated object will be picked at the top. Specified as 716 # an "ORDER BY" sql fragment, such as "last_name, first_name DESC"717 # * <tt>:dependent</tt> - if set to :destroy (or true)the associated object is destroyed when this object is. If set to718 # :delete the associated object is deleted *without* calling its destroy method. If set to :nullifythe associated719 # object's foreign key is set to NULL. Also, association is assigned.716 # an <tt>ORDER BY</tt> SQL fragment, such as <tt>last_name, first_name DESC</tt> 717 # * <tt>:dependent</tt> - if set to <tt>:destroy</tt> (or +true+), the associated object is destroyed when this object is. If set to 718 # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. If set to <tt>:nullify</tt>, the associated 719 # object's foreign key is set to +NULL+. Also, association is assigned. 720 720 # * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name 721 # of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_one association will use "person_id"722 # as the default foreign_key.721 # of this class in lower-case and +_id+ suffixed. So a +Person+ class that makes a +has_one+ association will use +person_id+ 722 # as the default +foreign_key+. 723 723 # * <tt>:include</tt> - specify second-order associations that should be eager loaded when this object is loaded. 724 # * <tt>:as</tt>: Specifies a polymorphic interface (See #belongs_to).724 # * <tt>:as</tt>: Specifies a polymorphic interface (See <tt>#belongs_to</tt>). 725 725 # 726 726 # Option examples: 727 727 # has_one :credit_card, :dependent => :destroy # destroys the associated credit card … … 753 753 deprecated_association_comparison_method(reflection.name, reflection.class_name) 754 754 end 755 755 756 # Adds the following methods for retrieval and query for a single associated object that this object holds an id to.756 # Adds the following methods for retrieval and query for a single associated object for which this object holds an id: 757 757 # +association+ is replaced with the symbol passed as the first argument, so 758 758 # <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>. 759 # * <tt>association(force_reload = false)</tt> - returns the associated object. Nilis returned if none is found.759 # * <tt>association(force_reload = false)</tt> - returns the associated object. +nil+ is returned if none is found. 760 760 # * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, and sets it as the foreign key. 761 # * <tt>association.nil?</tt> - returns trueif there is no associated object.761 # * <tt>association.nil?</tt> - returns +true+ if there is no associated object. 762 762 # * <tt>build_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated 763 # with +attributes+ and linked to this object through a foreign key but has not yet been saved.763 # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. 764 764 # * <tt>create_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated 765 # with +attributes+ and linked to this object through a foreign keyand that has already been saved (if it passed the validation).765 # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation). 766 766