提交 18a3333a 编写于 作者: M Michael Koziarski

Formatting, grammar and spelling fixes for the associations documentation....

Formatting, grammar and spelling fixes for the associations documentation. [seanhussey] Closes #8899


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7368 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 c11ca0e0
......@@ -70,7 +70,7 @@ def clear_aggregation_cache #:nodoc:
# end
#
# Now it's possible to access attributes from the database through the value objects instead. If you choose to name the
# composition the same as the attributes name, it will be the only way to access that attribute. That's the case with our
# composition the same as the attribute's name, it will be the only way to access that attribute. That's the case with our
# +balance+ attribute. You interact with the value objects just like you would any other attribute, though:
#
# customer.balance = Money.new(20) # sets the Money value object and the attribute
......@@ -92,19 +92,19 @@ def clear_aggregation_cache #:nodoc:
#
# == Writing value objects
#
# Value objects are immutable and interchangeable objects that represent a given value, such as a Money object representing
# $5. Two Money objects both representing $5 should be equal (through methods such as == and <=> from Comparable if ranking
# makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as Customer can
# Value objects are immutable and interchangeable objects that represent a given value, such as a +Money+ object representing
# $5. Two +Money+ objects both representing $5 should be equal (through methods such as == and <=> from +Comparable+ if ranking
# makes sense). This is unlike entity objects where equality is determined by identity. An entity class such as +Customer+ can
# easily have two different objects that both have an address on Hyancintvej. Entity identity is determined by object or
# relational unique identifiers (such as primary keys). Normal ActiveRecord::Base classes are entity objects.
# relational unique identifiers (such as primary keys). Normal <tt>ActiveRecord::Base</tt> classes are entity objects.
#
# It's also important to treat the value objects as immutable. Don't allow the Money object to have its amount changed after
# creation. Create a new money object with the new value instead. This is exemplified by the Money#exchanged_to method that
# It's also important to treat the value objects as immutable. Don't allow the +Money+ object to have its amount changed after
# creation. Create a new +Money+ object with the new value instead. This is exemplified by the <tt>Money#exchanged_to</tt> method that
# returns a new value object instead of changing its own values. Active Record won't persist value objects that have been
# changed through other means than the writer method.
# changed through means other than the writer method.
#
# The immutable requirement is enforced by Active Record by freezing any object assigned as a value object. Attempting to
# change it afterwards will result in a TypeError.
# change it afterwards will result in a <tt>TypeError</tt>.
#
# Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not keeping value objects
# immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
......@@ -119,8 +119,8 @@ module ClassMethods
# * <tt>:mapping</tt> - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name
# to a constructor parameter on the value class.
# * <tt>:allow_nil</tt> - specifies that the aggregate object will not be instantiated when all mapped
# attributes are nil. Setting the aggregate class to nil has the effect of writing nil to all mapped attributes.
# This defaults to false.
# attributes are +nil+. Setting the aggregate class to +nil+ has the effect of writing +nil+ to all mapped attributes.
# This defaults to +false+.
#
# Option examples:
# composed_of :temperature, :mapping => %w(reading celsius)
......
......@@ -76,7 +76,7 @@ def clear_association_cache #:nodoc:
# Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like
# "Project has one Project Manager" or "Project belongs to a Portfolio". Each macro adds a number of methods to the class which are
# specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby's own attr*
# 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>
# methods. Example:
#
# class Project < ActiveRecord::Base
......@@ -146,12 +146,12 @@ def clear_association_cache #:nodoc:
#
# ActiveRecord associations can be used to describe relations with one-to-one, one-to-many
# and many-to-many cardinality. Each model uses an association to describe its role in
# the relation. In each case, the belongs_to association is used in the model that has
# the relation. In each case, the +belongs_to+ association is used in the model that has
# the foreign key.
#
# === One-to-one
#
# Use has_one in the base, and belongs_to in the associated model.
# Use +has_one+ in the base, and +belongs_to+ in the associated model.
#
# class Employee < ActiveRecord::Base
# has_one :office
......@@ -162,7 +162,7 @@ def clear_association_cache #:nodoc:
#
# === One-to-many
#
# Use has_many in the base, and belongs_to in the associated model.
# Use +has_many+ in the base, and +belongs_to+ in the associated model.
#
# class Manager < ActiveRecord::Base
# has_many :employees
......@@ -175,7 +175,7 @@ def clear_association_cache #:nodoc:
#
# There are two ways to build a many-to-many relationship.
#
# The first way uses a has_many association with the :through option and a join model, so
# The first way uses a +has_many+ association with the <tt>:through</tt> option and a join model, so
# there are two stages of associations.
#
# class Assignment < ActiveRecord::Base
......@@ -191,7 +191,7 @@ def clear_association_cache #:nodoc:
# has_many :programmers, :through => :assignments
# end
#
# For the second way, use has_and_belongs_to_many in both models. This requires a join table
# For the second way, use +has_and_belongs_to_many+ in both models. This requires a join table
# that has no corresponding model or primary key.
#
# class Programmer < ActiveRecord::Base
......@@ -201,15 +201,15 @@ def clear_association_cache #:nodoc:
# has_and_belongs_to_many :programmers # foreign keys in the join table
# end
#
# It is not always a simple decision which way of building a many-to-many relationship is best.
# But if you need to work with the relationship model as its own entity, then you'll need to
# use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when
# Choosing which way to build a many-to-many relationship is not always simple.
# If you need to work with the relationship model as its own entity,
# use <tt>has_many :through</tt>. Use +has_and_belongs_to_many+ when working with legacy schemas or when
# you never work directly with the relationship itself.
#
# == Is it a belongs_to or has_one association?
# == Is it a +belongs_to+ or +has_one+ association?
#
# Both express a 1-1 relationship, the difference is mostly where to place the foreign key, which goes on the table for the class
# saying belongs_to. Example:
# Both express a 1-1 relationship. The difference is mostly where to place the foreign key, which goes on the table for the class
# declaring the +belongs_to+ relationship. Example:
#
# class User < ActiveRecord::Base
# # I reference an account.
......@@ -243,26 +243,26 @@ def clear_association_cache #:nodoc:
#
# === One-to-one associations
#
# * Assigning an object to a has_one association automatically saves that object and the object being replaced (if there is one), in
# order to update their primary keys - except if the parent object is unsaved (new_record? == true).
# * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns false and the assignment
# * Assigning an object to a +has_one+ association automatically saves that object and the object being replaced (if there is one), in
# order to update their primary keys - except if the parent object is unsaved (<tt>new_record? == true</tt>).
# * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns +false+ and the assignment
# is cancelled.
# * If you wish to assign an object to a has_one association without saving it, use the #association.build method (documented below).
# * Assigning an object to a belongs_to association does not save the object, since the foreign key field belongs on the parent. It does
# not save the parent either.
# * If you wish to assign an object to a +has_one+ association without saving it, use the <tt>#association.build</tt> method (documented below).
# * Assigning an object to a +belongs_to+ association does not save the object, since the foreign key field belongs on the parent. It
# does not save the parent either.
#
# === Collections
#
# * Adding an object to a collection (has_many or has_and_belongs_to_many) automatically saves that object, except if the parent object
# * Adding an object to a collection (+has_many+ or +has_and_belongs_to_many+) automatically saves that object, except if the parent object
# (the owner of the collection) is not yet stored in the database.
# * If saving any of the objects being added to a collection (via #push or similar) fails, then #push returns false.
# * You can add an object to a collection without automatically saving it by using the #collection.build method (documented below).
# * All unsaved (new_record? == true) members of the collection are automatically saved when the parent is saved.
# * If saving any of the objects being added to a collection (via <tt>#push</tt> or similar) fails, then <tt>#push</tt> returns +false+.
# * You can add an object to a collection without automatically saving it by using the <tt>#collection.build</tt> method (documented below).
# * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically saved when the parent is saved.
#
# === Association callbacks
#
# Similiar to the normal callbacks that hook into the lifecycle of an Active Record object, you can also define callbacks that get
# trigged when you add an object to or removing an object from a association collection. Example:
# trigged when you add an object to or remove an object from an association collection. Example:
#
# class Project
# has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
......@@ -278,14 +278,14 @@ def clear_association_cache #:nodoc:
# has_and_belongs_to_many :developers, :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
# end
#
# Possible callbacks are: before_add, after_add, before_remove and after_remove.
# Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
#
# Should any of the before_add callbacks throw an exception, the object does not get added to the collection. Same with
# the before_remove callbacks, if an exception is thrown the object doesn't get removed.
# Should any of the +before_add+ callbacks throw an exception, the object does not get added to the collection. Same with
# the +before_remove+ callbacks; if an exception is thrown the object doesn't get removed.
#
# === Association extensions
#
# The proxy objects that controls the access to associations can be extended through anonymous modules. This is especially
# The proxy objects that control the access to associations can be extended through anonymous modules. This is especially
# beneficial for adding new finders, creators, and other factory-type methods that are only used as part of this association.
# Example:
#
......@@ -319,7 +319,7 @@ def clear_association_cache #:nodoc:
# has_many :people, :extend => FindOrCreateByNameExtension
# end
#
# If you need to use multiple named extension modules, you can specify an array of modules with the :extend option.
# If you need to use multiple named extension modules, you can specify an array of modules with the <tt>:extend</tt> option.
# In the case of name conflicts between methods in the modules, methods in modules later in the array supercede
# those earlier in the array. Example:
#
......@@ -332,12 +332,12 @@ def clear_association_cache #:nodoc:
#
# * +proxy_owner+ - Returns the object the association is part of.
# * +proxy_reflection+ - Returns the reflection object that describes the association.
# * +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.
# * +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+.
#
# === Association Join Models
#
# Has Many associations can be configured with the :through option to use an explicit join model to retrieve the data. This
# operates similarly to a <tt>has_and_belongs_to_many</tt> association. The advantage is that you're able to add validations,
# Has Many associations can be configured with the <tt>:through</tt> option to use an explicit join model to retrieve the data. This
# operates similarly to a +has_and_belongs_to_many+ association. The advantage is that you're able to add validations,
# callbacks, and extra attributes on the join model. Consider the following schema:
#
# class Author < ActiveRecord::Base
......@@ -354,7 +354,7 @@ def clear_association_cache #:nodoc:
# @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to.
# @author.books # selects all books by using the Authorship join model
#
# You can also go through a has_many association on the join model:
# You can also go through a +has_many+ association on the join model:
#
# class Firm < ActiveRecord::Base
# has_many :clients
......@@ -377,25 +377,25 @@ def clear_association_cache #:nodoc:
# === Polymorphic Associations
#
# Polymorphic associations on models are not restricted on what types of models they can be associated with. Rather, they
# specify an interface that a has_many association must adhere to.
# specify an interface that a +has_many+ association must adhere to.
#
# class Asset < ActiveRecord::Base
# belongs_to :attachable, :polymorphic => true
# end
#
# class Post < ActiveRecord::Base
# has_many :assets, :as => :attachable # The <tt>:as</tt> option specifies the polymorphic interface to use.
# has_many :assets, :as => :attachable # The :as option specifies the polymorphic interface to use.
# end
#
# @asset.attachable = @post
#
# 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
# an attachable_id integer column and an attachable_type string column.
# an +attachable_id+ integer column and an +attachable_type+ string column.
#
# Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order
# for the associations to work as expected, ensure that you store the base model for the STI models in the
# type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts
# and member posts that use the posts table for STI. So there will be an additional 'type' column in the posts table.
# and member posts that use the posts table for STI. In this case, there must be a +type+ column in the posts table.
#
# class Asset < ActiveRecord::Base
# belongs_to :attachable, :polymorphic => true
......@@ -431,7 +431,7 @@ def clear_association_cache #:nodoc:
# == Eager loading of associations
#
# 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
# one of the easiest ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each needs to display their author
# 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
# triggers 101 database queries. Through the use of eager loading, the 101 queries can be reduced to 1. Example:
#
# class Post < ActiveRecord::Base
......@@ -451,16 +451,16 @@ def clear_association_cache #:nodoc:
#
# for post in Post.find(:all, :include => :author)
#
# This references the name of the belongs_to association that also used the :author symbol, so the find will now weave in a join something
# 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.
# 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
# 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.
#
# We can improve upon the situation further by referencing both associations in the finder with:
#
# for post in Post.find(:all, :include => [ :author, :comments ])
#
# 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.
# 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.
#
# To include a deep hierarchy of associations, using a hash:
# To include a deep hierarchy of associations, use a hash:
#
# for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ])
#
......@@ -472,12 +472,12 @@ def clear_association_cache #:nodoc:
# 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.
#
# Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So
# :order => "posts.id DESC" will work while :order => "id DESC" will not. Because eager loading generates the SELECT statement too, the
# :select option is ignored.
# <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
# <tt>:select</tt> option is ignored.
#
# You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions
# as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich
# associations" with has_and_belongs_to_many are not a good fit for eager loading.
# associations" with +has_and_belongs_to_many+ are not a good fit for eager loading.
#
# When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated
# before the actual model exists.
......@@ -485,7 +485,7 @@ def clear_association_cache #:nodoc:
# == Table Aliasing
#
# ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once,
# the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended
# the standard table name is used. The second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>. Indexes are appended
# for any more successive uses of the table name.
#
# Post.find :all, :include => :comments
......@@ -505,9 +505,9 @@ def clear_association_cache #:nodoc:
# TreeMixin.find :all, :include => {:children => {:parent => :children}}
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
# LEFT OUTER JOIN parents_mixins ...
# LEFT OUTER JOIN mixins childrens_mixins_2
# LEFT OUTER JOIN mixins childrens_mixins_2
#
# Has and Belongs to Many join tables use the same idea, but add a _join suffix:
# Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
#
# Post.find :all, :include => :categories
# # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
......@@ -519,7 +519,7 @@ def clear_association_cache #:nodoc:
# LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
# LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts
#
# If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations..
# 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:
#
# Post.find :all, :include => :comments, :joins => "inner join comments ..."
# # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ...
......@@ -544,8 +544,8 @@ def clear_association_cache #:nodoc:
# end
# end
#
# When Firm#clients is called, it'll in turn call <tt>MyApplication::Business::Company.find(firm.id)</tt>. If you want to associate
# with a class in another module scope this can be done by specifying the complete class name, such as:
# 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
# with a class in another module scope, this can be done by specifying the complete class name. Example:
#
# module MyApplication
# module Business
......@@ -559,41 +559,41 @@ def clear_association_cache #:nodoc:
# end
# end
#
# == Type safety with ActiveRecord::AssociationTypeMismatch
# == 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
# get a ActiveRecord::AssociationTypeMismatch.
# get an <tt>ActiveRecord::AssociationTypeMismatch</tt>.
#
# == Options
#
# All of the association macros can be specialized through options which makes more complex cases than the simple and guessable ones
# All of the association macros can be specialized through options. This makes cases more complex than the simple and guessable ones
# possible.
module ClassMethods
# Adds the following methods for retrieval and query of collections of associated objects.
# Adds the following methods for retrieval and query of collections of associated objects:
# +collection+ is replaced with the symbol passed as the first argument, so
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
# * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
# An empty array is returned if none are found.
# * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
# * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL.
# This will also destroy the objects if they're declared as belongs_to and dependent on this model.
# This will also destroy the objects if they're declared as +belongs_to+ and dependent on this model.
# * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate.
# * <tt>collection_singular_ids</tt> - returns an array of the associated objects ids
# * <tt>collection_singular_ids</tt> - returns an array of the associated objects' ids
# * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+
# * <tt>collection.clear</tt> - removes every object from the collection. This destroys the associated objects if they
# are associated with <tt>:dependent => :destroy</tt>, deletes them directly from the database if <tt>:dependent => :delete_all</tt>,
# and sets their foreign keys to NULL otherwise.
# * <tt>collection.empty?</tt> - returns true if there are no associated objects.
# or otherwise sets their foreign keys to NULL.
# * <tt>collection.empty?</tt> - returns +true+ if there are no associated objects.
# * <tt>collection.size</tt> - returns the number of associated objects.
# * <tt>collection.find</tt> - finds an associated object according to the same rules as Base.find.
# * <tt>collection.build(attributes = {}, ...)</tt> - returns one or more new objects of the collection type that have been instantiated
# with +attributes+ and linked to this object through a foreign key but have not yet been saved. *Note:* This only works if an
# associated object already exists, not if it's nil!
# with +attributes+ and linked to this object through a foreign key, but have not yet been saved. *Note:* This only works if an
# associated object already exists, not if it's +nil+!
# * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection 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).
# *Note:* This only works if an associated object already exists, not if it's nil!
# with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
# *Note:* This only works if an associated object already exists, not if it's +nil+!
#
# Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
# Example: A +Firm+ class declares <tt>has_many :clients</tt>, which will add:
# * <tt>Firm#clients</tt> (similar to <tt>Clients.find :all, :conditions => "firm_id = #{id}"</tt>)
# * <tt>Firm#clients<<</tt>
# * <tt>Firm#clients.delete</tt>
......@@ -612,47 +612,47 @@ module ClassMethods
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
# from the association name. So <tt>has_many :products</tt> will by default be linked to the +Product+ class, but
# if the real class name is +SpecialProduct+, you'll have to specify it with this option.
# * <tt>:conditions</tt> - specify the conditions that the associated objects must meet in order to be included as a "WHERE"
# sql fragment, such as "price > 5 AND name LIKE 'B%'".
# * <tt>:order</tt> - specify the order in which the associated objects are returned as a "ORDER BY" sql fragment,
# such as "last_name, first_name DESC"
# * <tt>:group</tt> - specify the attribute by which the associated objects are returned as a "GROUP BY" sql fragment,
# such as "category"
# * <tt>:conditions</tt> - specify the conditions that the associated objects must meet in order to be included as a +WHERE+
# SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>.
# * <tt>:order</tt> - specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
# such as <tt>last_name, first_name DESC</tt>
# * <tt>:group</tt> - specify the attribute by which the associated objects are returned as a <tt>GROUP BY</tt> SQL fragment,
# such as +category+
# * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
# of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_many association will use "person_id"
# as the default foreign_key.
# * <tt>:dependent</tt> - if set to :destroy all the associated objects are destroyed
# alongside this object by calling their destroy method. If set to :delete_all all associated
# objects are deleted *without* calling their destroy method. If set to :nullify all associated
# objects' foreign keys are set to NULL *without* calling their save callbacks.
# NOTE: :dependent => true is deprecated and has been replaced with :dependent => :destroy.
# May not be set if :exclusively_dependent is also set.
# * <tt>:exclusively_dependent</tt> - Deprecated; equivalent to :dependent => :delete_all. If set to true all
# the associated object are deleted in one SQL statement without having their
# before_destroy callback run. This should only be used on associations that depend solely on this class and don't need to do any
# clean-up in before_destroy. The upside is that it's much faster, especially if there's a counter_cache involved.
# May not be set if :dependent is also set.
# of this class in lower-case and +_id+ suffixed. So a +Person+ class that makes a +has_many+ association will use +person_id+
# as the default +foreign_key+.
# * <tt>:dependent</tt> - if set to <tt>:destroy</tt> all the associated objects are destroyed
# alongside this object by calling their destroy method. If set to <tt>:delete_all</tt> all associated
# objects are deleted *without* calling their destroy method. If set to <tt>:nullify</tt> all associated
# objects' foreign keys are set to +NULL+ *without* calling their save callbacks.
# NOTE: <tt>:dependent => true</tt> is deprecated and has been replaced with <tt>:dependent => :destroy</tt>.
# May not be set if <tt>:exclusively_dependent</tt> is also set.
# * <tt>:exclusively_dependent</tt> - Deprecated; equivalent to <tt>:dependent => :delete_all</tt>. If set to +true+ all
# the associated objects are deleted in one SQL statement without having their
# +before_destroy+ callback run. This should only be used on associations that depend solely on this class and don't need to do any
# clean-up in +before_destroy+. The upside is that it's much faster, especially if there's a +counter_cache+ involved.
# May not be set if <tt>:dependent</tt> is also set.
# * <tt>:finder_sql</tt> - specify a complete SQL statement to fetch the association. This is a good way to go for complex
# associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added.
# * <tt>:counter_sql</tt> - specify a complete SQL statement to fetch the size of the association. If +:finder_sql+ is
# specified but +:counter_sql+, +:counter_sql+ will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM.
# * <tt>:extend</tt> - specify a named module for extending the proxy, see "Association extensions".
# * <tt>:counter_sql</tt> - specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
# 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>.
# * <tt>:extend</tt> - specify a named module for extending the proxy. See "Association extensions".
# * <tt>:include</tt> - specify second-order associations that should be eager loaded when the collection is loaded.
# * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
# * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
# * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
# * <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.
# * <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 not
# include the joined columns.
# * <tt>:as</tt>: Specifies a polymorphic interface (See #belongs_to).
# * <tt>:through</tt>: Specifies a Join Model to perform the query through. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
# * <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,
# but not include the joined columns.
# * <tt>:as</tt>: Specifies a polymorphic interface (See <tt>#belongs_to</tt>).
# * <tt>:through</tt>: Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
# are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a <tt>belongs_to</tt>
# or <tt>has_many</tt> association on the join model.
# * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be
# inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+ or
# +:subscriber+ on +Subscription+, unless a +:source+ is given.
# * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source association
# is a polymorphic belongs_to.
# * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through.
# inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either <tt>:subscribers</tt> or
# <tt>:subscriber</tt> on +Subscription+, unless a <tt>:source</tt> is given.
# * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
# association is a polymorphic +belongs_to+.
# * <tt>:uniq</tt> - if set to +true+, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
#
# Option examples:
# has_many :comments, :order => "posted_on"
......@@ -684,18 +684,18 @@ def has_many(association_id, options = {}, &extension)
add_deprecated_api_for_has_many(reflection.name)
end
# Adds the following methods for retrieval and query of a single associated object.
# Adds the following methods for retrieval and query of a single associated object:
# +association+ is replaced with the symbol passed as the first argument, so
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
# * <tt>association(force_reload = false)</tt> - returns the associated object. Nil is returned if none is found.
# * <tt>association(force_reload = false)</tt> - returns the associated object. +nil+ is returned if none is found.
# * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, sets it as the foreign key,
# and saves the associate object.
# * <tt>association.nil?</tt> - returns true if there is no associated object.
# * <tt>association.nil?</tt> - returns +true+ if there is no associated object.
# * <tt>build_association(attributes = {})</tt> - 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. Note: This ONLY works if
# an association already exists. It will NOT work if the association is nil.
# with +attributes+ and linked to this object through a foreign key, but has not yet been saved. Note: This ONLY works if
# an association already exists. It will NOT work if the association is +nil+.
# * <tt>create_association(attributes = {})</tt> - 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).
# with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
#
# Example: An Account class declares <tt>has_one :beneficiary</tt>, which will add:
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.find(:first, :conditions => "account_id = #{id}")</tt>)
......@@ -710,18 +710,18 @@ def has_many(association_id, options = {}, &extension)
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the +Manager+ class, but
# if the real class name is +Person+, you'll have to specify it with this option.
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
# sql fragment, such as "rank = 5".
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a +WHERE+
# SQL fragment, such as <tt>rank = 5</tt>.
# * <tt>:order</tt> - 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"
# * <tt>:dependent</tt> - if set to :destroy (or true) the associated object is destroyed when this object is. If set to
# :delete the associated object is deleted *without* calling its destroy method. If set to :nullify the associated
# object's foreign key is set to NULL. Also, association is assigned.
# an <tt>ORDER BY</tt> SQL fragment, such as <tt>last_name, first_name DESC</tt>
# * <tt>:dependent</tt> - if set to <tt>:destroy</tt> (or +true+), the associated object is destroyed when this object is. If set to
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. If set to <tt>:nullify</tt>, the associated
# object's foreign key is set to +NULL+. Also, association is assigned.
# * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
# of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_one association will use "person_id"
# as the default foreign_key.
# of this class in lower-case and +_id+ suffixed. So a +Person+ class that makes a +has_one+ association will use +person_id+
# as the default +foreign_key+.
# * <tt>:include</tt> - specify second-order associations that should be eager loaded when this object is loaded.
# * <tt>:as</tt>: Specifies a polymorphic interface (See #belongs_to).
# * <tt>:as</tt>: Specifies a polymorphic interface (See <tt>#belongs_to</tt>).
#
# Option examples:
# has_one :credit_card, :dependent => :destroy # destroys the associated credit card
......@@ -753,16 +753,16 @@ def has_one(association_id, options = {})
deprecated_association_comparison_method(reflection.name, reflection.class_name)
end
# Adds the following methods for retrieval and query for a single associated object that this object holds an id to.
# Adds the following methods for retrieval and query for a single associated object for which this object holds an id:
# +association+ is replaced with the symbol passed as the first argument, so
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
# * <tt>association(force_reload = false)</tt> - returns the associated object. Nil is returned if none is found.
# * <tt>association(force_reload = false)</tt> - returns the associated object. +nil+ is returned if none is found.
# * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, and sets it as the foreign key.
# * <tt>association.nil?</tt> - returns true if there is no associated object.
# * <tt>association.nil?</tt> - returns +true+ if there is no associated object.
# * <tt>build_association(attributes = {})</tt> - 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.
# with +attributes+ and linked to this object through a foreign key, but has not yet been saved.
# * <tt>create_association(attributes = {})</tt> - 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).
# with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
#
# Example: A Post class declares <tt>belongs_to :author</tt>, which will add:
# * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
......@@ -777,20 +777,20 @@ def has_one(association_id, options = {})
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
# from the association name. So <tt>has_one :author</tt> 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.
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
# sql fragment, such as "authorized = 1".
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a +WHERE+
# SQL fragment, such as <tt>authorized = 1</tt>.
# * <tt>:order</tt> - 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"
# an <tt>ORDER BY</tt> SQL fragment, such as <tt>last_name, first_name DESC</tt>
# * <tt>:foreign_key</tt> - 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.
# * <tt>:counter_cache</tt> - 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., <tt>:counter_cache => :my_custom_counter</tt>.)
# 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+.
# * <tt>:counter_cache</tt> - 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 <tt>#{table_name}_count</tt> (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 providing
# a column name instead of a +true+/+false+ value to this option (e.g., <tt>:counter_cache => :my_custom_counter</tt>.)
# * <tt>:include</tt> - specify second-order associations that should be eager loaded when this object is loaded.
# * <tt>:polymorphic</tt> - specify this association is a polymorphic association by passing true.
# * <tt>:polymorphic</tt> - specify this association is a polymorphic association by passing +true+.
#
# Option examples:
# belongs_to :firm, :foreign_key => "client_of"
......@@ -863,8 +863,8 @@ def belongs_to(association_id, options = {})
end
# Associates two classes via an intermediate join table. Unless the join table is explicitly specified as
# an option, it is guessed using the lexical order of the class names. So a join between Developer and Project
# will give the default join table name of "developers_projects" because "D" outranks "P". Note that this precedence
# an option, it is guessed using the lexical order of the class names. So a join between +Developer+ and +Project+
# will give the default join table name of +developers_projects+ because "D" outranks "P". Note that this precedence
# is calculated using the <tt><</tt> operator for <tt>String</tt>. This means that if the strings are of different lengths,
# and the strings are equal when compared up to the shortest length, then the longer string is considered of higher
# lexical precedence than the shorter one. For example, one would expect the tables <tt>paper_boxes</tt> and <tt>papers</tt>
......@@ -873,37 +873,37 @@ def belongs_to(association_id, options = {})
# custom <tt>join_table</tt> option if you need to.
#
# Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through
# has_and_belongs_to_many associations. Records returned from join tables with additional attributes will be marked as
# ReadOnly (because we can't save changes to the additional attrbutes). It's strongly recommended that you upgrade any
# +has_and_belongs_to_many+ associations. Records returned from join tables with additional attributes will be marked as
# +ReadOnly+ (because we can't save changes to the additional attrbutes). It's strongly recommended that you upgrade any
# associations with attributes to a real join model (see introduction).
#
# Adds the following methods for retrieval and query.
# Adds the following methods for retrieval and query:
# +collection+ is replaced with the symbol passed as the first argument, so
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
# * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
# An empty array is returned if none is found.
# An empty array is returned if none are found.
# * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by creating associations in the join table
# (collection.push and collection.concat are aliases to this method).
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
# * <tt>collection.push_with_attributes(object, join_attributes)</tt> - adds one to the collection by creating an association in the join table that
# also holds the attributes from <tt>join_attributes</tt> (should be a hash with the column names as keys). This can be used to have additional
# attributes on the join, which will be injected into the associated objects when they are retrieved through the collection.
# (collection.concat_with_attributes is an alias to this method). This method is now deprecated.
# (<tt>collection.concat_with_attributes</tt> is an alias to this method). This method is now deprecated.
# * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by removing their associations from the join table.
# This does not destroy the objects.
# * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate.
# * <tt>collection_singular_ids</tt> - returns an array of the associated objects ids
# * <tt>collection=objects</tt> - replaces the collection's content by deleting and adding objects as appropriate.
# * <tt>collection_singular_ids</tt> - returns an array of the associated objects' ids
# * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+
# * <tt>collection.clear</tt> - removes every object from the collection. This does not destroy the objects.
# * <tt>collection.empty?</tt> - returns true if there are no associated objects.
# * <tt>collection.empty?</tt> - returns +true+ if there are no associated objects.
# * <tt>collection.size</tt> - returns the number of associated objects.
# * <tt>collection.find(id)</tt> - finds an associated object responding to the +id+ and that
# meets the condition that it has to be associated with this object.
# * <tt>collection.build(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
# with +attributes+ and linked to this object through the join table but has not yet been saved.
# with +attributes+ and linked to this object through the join table, but has not yet been saved.
# * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
# with +attributes+ and linked to this object through the join table and that has already been saved (if it passed the validation).
# with +attributes+, linked to this object through the join table, and that has already been saved (if it passed the validation).
#
# Example: An Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
# Example: A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
# * <tt>Developer#projects</tt>
# * <tt>Developer#projects<<</tt>
# * <tt>Developer#projects.delete</tt>
......@@ -923,30 +923,30 @@ def belongs_to(association_id, options = {})
# from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
# +Project+ class, but if the real class name is +SuperProject+, you'll have to specify it with this option.
# * <tt>:join_table</tt> - specify the name of the join table if the default based on lexical order isn't what you want.
# WARNING: If you're overwriting the table name of either class, the table_name method MUST be declared underneath any
# has_and_belongs_to_many declaration in order to work.
# WARNING: If you're overwriting the table name of either class, the +table_name+ method MUST be declared underneath any
# +has_and_belongs_to_many+ declaration in order to work.
# * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
# of this class in lower-case and "_id" suffixed. So a +Person+ class that makes a has_and_belongs_to_many association
# will use "person_id" as the default foreign_key.
# of this class in lower-case and +_id+ suffixed. So a +Person+ class that makes a +has_and_belongs_to_many+ association
# will use +person_id+ as the default +foreign_key+.
# * <tt>:association_foreign_key</tt> - specify the association 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 if the associated class is +Project+,
# the has_and_belongs_to_many association will use "project_id" as the default association foreign_key.
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a "WHERE"
# sql fragment, such as "authorized = 1".
# * <tt>:order</tt> - specify the order in which the associated objects are returned as a "ORDER BY" sql fragment, such as "last_name, first_name DESC"
# * <tt>:uniq</tt> - if set to true, duplicate associated objects will be ignored by accessors and query methods
# * <tt>:finder_sql</tt> - overwrite the default generated SQL used to fetch the association with a manual one
# * <tt>:delete_sql</tt> - overwrite the default generated SQL used to remove links between the associated
# classes with a manual one
# * <tt>:insert_sql</tt> - overwrite the default generated SQL used to add links between the associated classes
# with a manual one
# guessed to be the name of the associated class in lower-case and +_id+ suffixed. So if the associated class is +Project+,
# the +has_and_belongs_to_many+ association will use +project_id+ as the default association +foreign_key+.
# * <tt>:conditions</tt> - specify the conditions that the associated object must meet in order to be included as a +WHERE+
# SQL fragment, such as <tt>authorized = 1</tt>.
# * <tt>:order</tt> - specify the order in which the associated objects are returned as a <tt>ORDER BY</tt> SQL fragment, such as <tt>last_name, first_name DESC</tt>
# * <tt>:uniq</tt> - if set to +true+, duplicate associated objects will be ignored by accessors and query methods
# * <tt>:finder_sql</tt> - overwrite the default generated SQL statement used to fetch the association with a manual statement
# * <tt>:delete_sql</tt> - overwrite the default generated SQL statement used to remove links between the associated
# classes with a manual statement
# * <tt>:insert_sql</tt> - overwrite the default generated SQL statement used to add links between the associated classes
# with a manual statement
# * <tt>:extend</tt> - anonymous module for extending the proxy, see "Association extensions".
# * <tt>:include</tt> - specify second-order associations that should be eager loaded when the collection is loaded.
# * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.
# * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
# * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
# * <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.
# * <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 not
# include the joined columns.
# * <tt>:select</tt>: By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example, you want to do a join
# but not include the joined columns.
#
# Option examples:
# has_and_belongs_to_many :projects
......
......@@ -65,7 +65,7 @@ def delete(*records)
# Removes all records from this association. Returns +self+ so method calls may be chained.
def clear
return self if length.zero? # forces load_target if hasn't happened already
return self if length.zero? # forces load_target if it hasn't happened already
if @reflection.options[:dependent] && @reflection.options[:dependent] == :delete_all
destroy_all
......
......@@ -139,7 +139,7 @@ def load_target
end
# Can be overwritten by associations that might have the foreign key available for an association without
# having the object itself (and still being a new record). Currently, only belongs_to present this scenario.
# having the object itself (and still being a new record). Currently, only belongs_to presents this scenario.
def foreign_key_present
false
end
......
......@@ -14,7 +14,7 @@ def build(attributes = {})
end
def create(attributes = {})
# Can't use Base.create since the foreign key may be a protected attribute.
# Can't use Base.create because the foreign key may be a protected attribute.
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr) }
else
......@@ -138,8 +138,8 @@ def construct_scope
end
# Join tables with additional columns on top of the two foreign keys must be considered ambigious unless a select
# clause has been explicitly defined. Otherwise you can get broken records back, if, say, the join column also has
# and id column, which will then overwrite the id column of the records coming back.
# clause has been explicitly defined. Otherwise you can get broken records back, if, for example, the join column also has
# an id column. This will then overwrite the id column of the records coming back.
def finding_with_ambigious_select?(select_clause)
!select_clause && @owner.connection.columns(@reflection.options[:join_table], "Join Table Columns").size != 2
end
......
......@@ -67,7 +67,7 @@ def <<(*records)
[:push, :concat].each { |method| alias_method method, :<< }
# Remove +records+ from this association. Does not destroy +records+.
# Removes +records+ from this association. Does not destroy +records+.
def delete(*records)
records = flatten_deeper(records)
records.each { |associate| raise_on_type_mismatch(associate) }
......
......@@ -76,7 +76,7 @@ def construct_scope
end
def new_record(replace_existing)
# make sure we load the target first, if we plan on replacing the existing
# Make sure we load the target first, if we plan on replacing the existing
# instance. Otherwise, if the target has not previously been loaded
# elsewhere, the instance we create will get orphaned.
load_target if replace_existing
......
require 'observer'
module ActiveRecord
# Callbacks are hooks into the lifecycle of an Active Record object that allows you to trigger logic
# Callbacks are hooks into the lifecycle of an Active Record object that allow you to trigger logic
# before or after an alteration of the object state. This can be used to make sure that associated and
# dependent objects are deleted when destroy is called (by overwriting before_destroy) or to massage attributes
# before they're validated (by overwriting before_validation). As an example of the callbacks initiated, consider
# the Base#save call:
#
# * (-) save
# * (-) valid?
# * (1) before_validation
# * (2) before_validation_on_create
# * (-) validate
# * (-) validate_on_create
# * (3) after_validation
# * (4) after_validation_on_create
# * (5) before_save
# * (6) before_create
# * (-) create
# * (7) after_create
# * (8) after_save
# dependent objects are deleted when destroy is called (by overwriting +before_destroy+) or to massage attributes
# before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider
# the <tt>Base#save</tt> call:
#
# * (-) <tt>save</tt>
# * (-) <tt>valid</tt>
# * (1) <tt>before_validation</tt>
# * (2) <tt>before_validation_on_create</tt>
# * (-) <tt>validate</tt>
# * (-) <tt>validate_on_create</tt>
# * (3) <tt>after_validation</tt>
# * (4) <tt>after_validation_on_create</tt>
# * (5) <tt>before_save</tt>
# * (6) <tt>before_create</tt>
# * (-) <tt>create</tt>
# * (7) <tt>after_create</tt>
# * (8) <tt>after_save</tt>
#
# That's a total of eight callbacks, which gives you immense power to react and prepare for each state in the
# Active Record lifecycle.
......@@ -62,8 +62,8 @@ module ActiveRecord
# before_destroy :destroy_readers
# end
#
# Now, when Topic#destroy is run only +destroy_author+ is called. When Reply#destroy is run both +destroy_author+ and
# +destroy_readers+ is called. Contrast this to the situation where we've implemented the save behavior through overwriteable
# Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is run, both +destroy_author+ and
# +destroy_readers+ are called. Contrast this to the situation where we've implemented the save behavior through overwriteable
# methods:
#
# class Topic < ActiveRecord::Base
......@@ -74,9 +74,9 @@ module ActiveRecord
# def before_destroy() destroy_readers end
# end
#
# In that case, Reply#destroy would only run +destroy_readers+ and _not_ +destroy_author+. So use the callback macros when
# you want to ensure that a certain callback is called for the entire hierarchy and the regular overwriteable methods when you
# want to leave it up to each descendent to decide whether they want to call +super+ and trigger the inherited callbacks.
# In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+. So, use the callback macros when
# you want to ensure that a certain callback is called for the entire hierarchy, and use the regular overwriteable methods
# when you want to leave it up to each descendent to decide whether they want to call +super+ and trigger the inherited callbacks.
#
# *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the callbacks before specifying the
# associations. Otherwise, you might trigger the loading of a child before the parent has registered the callbacks and they won't
......@@ -143,7 +143,7 @@ module ActiveRecord
# before_destroy 'self.class.delete_all "parent_id = #{id}"'
# end
#
# Notice that single plings (') are used so the #{id} part isn't evaluated until the callback is triggered. Also note that these
# Notice that single plings (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback is triggered. Also note that these
# inline callbacks can be stacked just like the regular ones:
#
# class Topic < ActiveRecord::Base
......@@ -151,23 +151,23 @@ module ActiveRecord
# 'puts "Evaluated after parents are destroyed"'
# end
#
# == The after_find and after_initialize exceptions
# == The +after_find+ and +after_initialize+ exceptions
#
# Because after_find and after_initialize are called for each object found and instantiated by a finder, such as Base.find(:all), we've had
# to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, after_find and
# after_initialize will only be run if an explicit implementation is defined (<tt>def after_find</tt>). In that case, all of the
# 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
# to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, +after_find+ and
# +after_initialize+ will only be run if an explicit implementation is defined (<tt>def after_find</tt>). In that case, all of the
# callback types will be called.
#
# == before_validation* returning statements
# == <tt>before_validation*</tt> returning statements
#
# 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.
# If Base#save! is called it will raise a RecordNotSave error.
# 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+.
# If <tt>Base#save!</tt> is called it will raise a +RecordNotSave+ exception.
# Nothing will be appended to the errors object.
#
# == Cancelling callbacks
#
# If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns
# false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks
# 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
# +false+, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks
# defined as methods on the model, which are called last.
module Callbacks
CALLBACKS = %w(
......@@ -215,10 +215,10 @@ def instantiate_with_callbacks(record)
end
end
# Is called when the object was instantiated by one of the finders, like Base.find.
# Is called when the object was instantiated by one of the finders, like <tt>Base.find</tt>.
#def after_find() end
# Is called after the object has been instantiated by a call to Base.new.
# Is called after the object has been instantiated by a call to <tt>Base.new</tt>.
#def after_initialize() end
def initialize_with_callbacks(attributes = nil) #:nodoc:
......@@ -229,10 +229,10 @@ def initialize_with_callbacks(attributes = nil) #:nodoc:
end
private :initialize_with_callbacks
# Is called _before_ Base.save (regardless of whether it's a create or update save).
# Is called _before_ <tt>Base.save</tt> (regardless of whether it's a +create+ or +update+ save).
def before_save() end
# Is called _after_ Base.save (regardless of whether it's a create or update save).
# Is called _after_ <tt>Base.save</tt> (regardless of whether it's a +create+ or +update+ save).
#
# class Contact < ActiveRecord::Base
# after_save { logger.info( 'New contact saved!' ) }
......@@ -246,10 +246,10 @@ def create_or_update_with_callbacks #:nodoc:
end
private :create_or_update_with_callbacks
# Is called _before_ Base.save on new objects that haven't been saved yet (no record exists).
# Is called _before_ <tt>Base.save</tt> on new objects that haven't been saved yet (no record exists).
def before_create() end
# Is called _after_ Base.save on new objects that haven't been saved yet (no record exists).
# Is called _after_ <tt>Base.save</tt> on new objects that haven't been saved yet (no record exists).
def after_create() end
def create_with_callbacks #:nodoc:
return false if callback(:before_create) == false
......@@ -259,10 +259,10 @@ def create_with_callbacks #:nodoc:
end
private :create_with_callbacks
# Is called _before_ Base.save on existing objects that have a record.
# Is called _before_ <tt>Base.save</tt> on existing objects that have a record.
def before_update() end
# Is called _after_ Base.save on existing objects that have a record.
# Is called _after_ <tt>Base.save</tt> on existing objects that have a record.
def after_update() end
def update_with_callbacks #:nodoc:
......@@ -273,25 +273,25 @@ def update_with_callbacks #:nodoc:
end
private :update_with_callbacks
# Is called _before_ Validations.validate (which is part of the Base.save call).
# Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call).
def before_validation() end
# Is called _after_ Validations.validate (which is part of the Base.save call).
# Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call).
def after_validation() end
# Is called _before_ Validations.validate (which is part of the Base.save call) on new objects
# Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on new objects
# that haven't been saved yet (no record exists).
def before_validation_on_create() end
# Is called _after_ Validations.validate (which is part of the Base.save call) on new objects
# Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on new objects
# that haven't been saved yet (no record exists).
def after_validation_on_create() end
# Is called _before_ Validations.validate (which is part of the Base.save call) on
# Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on
# existing objects that have a record.
def before_validation_on_update() end
# Is called _after_ Validations.validate (which is part of the Base.save call) on
# Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on
# existing objects that have a record.
def after_validation_on_update() end
......@@ -308,13 +308,13 @@ def valid_with_callbacks? #:nodoc:
return result
end
# Is called _before_ Base.destroy.
# Is called _before_ <tt>Base.destroy</tt>.
#
# Note: If you need to _destroy_ or _nullify_ associated records first,
# use the _:dependent_ option on your associations.
# use the <tt>:dependent</tt> option on your associations.
def before_destroy() end
# Is called _after_ Base.destroy (and all the attributes have been frozen).
# Is called _after_ <tt>Base.destroy</tt> (and all the attributes have been frozen).
#
# class Contact < ActiveRecord::Base
# after_destroy { |record| logger.info( "Contact #{record.id} was destroyed." ) }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册