From 6e754551254a8cc64e034163f5d0dc155b450388 Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Mon, 28 Jul 2008 12:26:59 +0100 Subject: Merge docrails changes --- activerecord/lib/active_record/associations.rb | 418 +++++++++++++++++-------- activerecord/lib/active_record/base.rb | 29 +- activerecord/lib/active_record/transactions.rb | 9 +- 3 files changed, 317 insertions(+), 139 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index d916275ab9..4e33dfe69f 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -73,6 +73,7 @@ module ActiveRecord end end + # See ActiveRecord::Associations::ClassMethods for documentation. module Associations # :nodoc: def self.included(base) base.extend(ClassMethods) @@ -150,6 +151,7 @@ module ActiveRecord # #others.destroy_all | X | X | X # #others.find(*args) | X | X | X # #others.find_first | X | | + # #others.exist? | X | X | X # #others.uniq | X | X | X # #others.reset | X | X | X # @@ -612,31 +614,53 @@ module ActiveRecord # 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: - # +collection+ is replaced with the symbol passed as the first argument, so - # has_many :clients would add among others clients.empty?. - # * collection(force_reload = false) - Returns an array of all the associated objects. + # Specifies a one-to-many association. The following methods for retrieval and query of + # collections of associated objects will be added: + # + # [collection(force_reload = false)] + # Returns an array of all the associated objects. # An empty array is returned if none are found. - # * collection<<(object, ...) - Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. - # * collection.delete(object, ...) - Removes one or more objects from the collection by setting their foreign keys to +NULL+. + # [collection<<(object, ...)] + # Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. + # [collection.delete(object, ...)] + # 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. - # * collection=objects - Replaces the collections content by deleting and adding objects as appropriate. - # * collection_singular_ids - Returns an array of the associated objects' ids - # * collection_singular_ids=ids - Replace the collection with the objects identified by the primary keys in +ids+ - # * collection.clear - Removes every object from the collection. This destroys the associated objects if they - # are associated with :dependent => :destroy, deletes them directly from the database if :dependent => :delete_all, - # otherwise sets their foreign keys to +NULL+. - # * collection.empty? - Returns +true+ if there are no associated objects. - # * collection.size - Returns the number of associated objects. - # * collection.find - Finds an associated object according to the same rules as Base.find. - # * collection.build(attributes = {}, ...) - 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+! - # * collection.create(attributes = {}) - Returns a new object of the collection type that has been instantiated - # 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+! + # [collection=objects] + # Replaces the collections content by deleting and adding objects as appropriate. + # [collection_singular_ids] + # Returns an array of the associated objects' ids + # [collection_singular_ids=ids] + # Replace the collection with the objects identified by the primary keys in +ids+ + # [collection.clear] + # Removes every object from the collection. This destroys the associated objects if they + # are associated with :dependent => :destroy, deletes them directly from the + # database if :dependent => :delete_all, otherwise sets their foreign keys to +NULL+. + # [collection.empty?] + # Returns +true+ if there are no associated objects. + # [collection.size] + # Returns the number of associated objects. + # [collection.find(...)] + # Finds an associated object according to the same rules as ActiveRecord::Base.find. + # [collection.exist?(...)] + # Checks whether an associated object with the given conditions exists. + # Uses the same rules as ActiveRecord::Base.exists?. + # [collection.build(attributes = {}, ...)] + # 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+! + # [collection.create(attributes = {})] + # Returns a new object of the collection type that has been instantiated + # 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+! + # + # (*Note*: +collection+ is replaced with the symbol passed as the first argument, so + # has_many :clients would add among others clients.empty?.) + # + # === Example # - # Example: A Firm class declares has_many :clients, which will add: + # A Firm class declares has_many :clients, which will add: # * Firm#clients (similar to Clients.find :all, :conditions => "firm_id = #{id}") # * Firm#clients<< # * Firm#clients.delete @@ -647,54 +671,77 @@ module ActiveRecord # * Firm#clients.empty? (similar to firm.clients.size == 0) # * Firm#clients.size (similar to Client.count "firm_id = #{id}") # * Firm#clients.find (similar to Client.find(id, :conditions => "firm_id = #{id}")) + # * Firm#clients.exist?(:name => 'ACME') (similar to Client.exist?(:name => 'ACME', :firm_id => firm.id)) # * Firm#clients.build (similar to Client.new("firm_id" => id)) # * Firm#clients.create (similar to c = Client.new("firm_id" => id); c.save; c) # The declaration can also include an options hash to specialize the behavior of the association. # - # Options are: - # * :class_name - Specify the class name of the association. Use it only if that name can't be inferred + # === Supported options + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred # from the association name. So has_many :products 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. - # * :conditions - Specify the conditions that the associated objects must meet in order to be included as a +WHERE+ + # [:conditions] + # 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%'. Record creations from the association are scoped if a hash # is used. has_many :posts, :conditions => {:published => true} will create published posts with @blog.posts.create # or @blog.posts.build. - # * :order - Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, + # [:order] + # Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, # such as last_name, first_name DESC. - # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name + # [:foreign_key] + # 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. - # * :primary_key - Specify the method that returns the primary key used for the association. By default this is +id+. - # * :dependent - If set to :destroy all the associated objects are destroyed + # [:primary_key] + # Specify the method that returns the primary key used for the association. By default this is +id+. + # [:dependent] + # 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. *Warning:* This option is ignored when also using # the :through option. - # * :finder_sql - Specify a complete SQL statement to fetch the association. This is a good way to go for complex + # [:finder_sql] + # 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. - # * :counter_sql - Specify a complete SQL statement to fetch the size of the association. If :finder_sql is + # [:counter_sql] + # Specify a complete SQL statement to fetch the size of the association. If :finder_sql is # specified but not :counter_sql, :counter_sql will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM. - # * :extend - Specify a named module for extending the proxy. See "Association extensions". - # * :include - Specify second-order associations that should be eager loaded when the collection is loaded. - # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :limit - An integer determining the limit on the number of rows that should be returned. - # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. - # * :select - By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join + # [:extend] + # Specify a named module for extending the proxy. See "Association extensions". + # [:include] + # Specify second-order associations that should be eager loaded when the collection is loaded. + # [:group] + # An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. + # [:limit] + # An integer determining the limit on the number of rows that should be returned. + # [:offset] + # An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. + # [:select] + # 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. Do not forget to include the primary and foreign keys, otherwise it will raise an error. - # * :as - Specifies a polymorphic interface (See belongs_to). - # * :through - Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key + # [:as] + # Specifies a polymorphic interface (See belongs_to). + # [:through] + # Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key # are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to # or has_many association on the join model. - # * :source - Specifies the source association name used by has_many :through queries. Only use it if the name cannot be + # [:source] + # Specifies the source association name used by has_many :through queries. Only use it if the name cannot be # inferred from the association. has_many :subscribers, :through => :subscriptions will look for either :subscribers or # :subscriber on Subscription, unless a :source is given. - # * :source_type - Specifies type of the source association used by has_many :through queries where the source + # [:source_type] + # Specifies type of the source association used by has_many :through queries where the source # association is a polymorphic +belongs_to+. - # * :uniq - If true, duplicates will be omitted from the collection. Useful in conjunction with :through. - # * :readonly - If true, all the associated objects are readonly through the association. - # * :validate - If false, don't validate the associated objects when saving the parent object. true by default. - # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). - # + # [:uniq] + # If true, duplicates will be omitted from the collection. Useful in conjunction with :through. + # [:readonly] + # If true, all the associated objects are readonly through the association. + # [:validate] + # If false, don't validate the associated objects when saving the parent object. true by default. + # [:accessible] + # Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). + # Option examples: # has_many :comments, :order => "posted_on" # has_many :comments, :include => :author @@ -725,58 +772,91 @@ module ActiveRecord end end - # 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 - # has_one :manager would add among others manager.nil?. - # * association(force_reload = false) - Returns the associated object. +nil+ is returned if none is found. - # * association=(associate) - Assigns the associate object, extracts the primary key, sets it as the foreign key, + # Specifies a one-to-one association with another class. This method should only be used + # if the other class contains the foreign key. If the current class contains the foreign key, + # then you should use +belongs_to+ instead. See also ActiveRecord::Associations::ClassMethods's overview + # on when to use has_one and when to use belongs_to. + # + # The following methods for retrieval and query of a single associated object will be added: + # + # [association(force_reload = false)] + # Returns the associated object. +nil+ is returned if none is found. + # [association=(associate)] + # Assigns the associate object, extracts the primary key, sets it as the foreign key, # and saves the associate object. - # * association.nil? - Returns +true+ if there is no associated object. - # * build_association(attributes = {}) - Returns a new object of the associated type that has been instantiated - # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. Note: This ONLY works if - # an association already exists. It will NOT work if the association is +nil+. - # * create_association(attributes = {}) - Returns a new object of the associated type that has been instantiated - # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation). + # [association.nil?] + # Returns +true+ if there is no associated object. + # [build_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated + # with +attributes+ and linked to this object through a foreign key, but has not + # yet been saved. Note: This ONLY works if an association already exists. + # It will NOT work if the association is +nil+. + # [create_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated + # with +attributes+, linked to this object through a foreign key, and that + # has already been saved (if it passed the validation). + # + # (+association+ is replaced with the symbol passed as the first argument, so + # has_one :manager would add among others manager.nil?.) # - # Example: An Account class declares has_one :beneficiary, which will add: + # === Example + # + # An Account class declares has_one :beneficiary, which will add: # * Account#beneficiary (similar to Beneficiary.find(:first, :conditions => "account_id = #{id}")) # * Account#beneficiary=(beneficiary) (similar to beneficiary.account_id = account.id; beneficiary.save) # * Account#beneficiary.nil? # * Account#build_beneficiary (similar to Beneficiary.new("account_id" => id)) # * Account#create_beneficiary (similar to b = Beneficiary.new("account_id" => id); b.save; b) # + # === Options + # # The declaration can also include an options hash to specialize the behavior of the association. # # Options are: - # * :class_name - Specify the class name of the association. Use it only if that name can't be inferred + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred # from the association name. So has_one :manager 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. - # * :conditions - Specify the conditions that the associated object must meet in order to be included as a +WHERE+ + # [:conditions] + # Specify the conditions that the associated object must meet in order to be included as a +WHERE+ # SQL fragment, such as rank = 5. - # * :order - Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, + # [:order] + # Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, # such as last_name, first_name DESC. - # * :dependent - If set to :destroy, the associated object is destroyed when this object is. If set to + # [:dependent] + # If set to :destroy, 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. - # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name + # [:foreign_key] + # 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. - # * :primary_key - Specify the method that returns the primary key used for the association. By default this is +id+. - # * :include - Specify second-order associations that should be eager loaded when this object is loaded. - # * :as - Specifies a polymorphic interface (See belongs_to). - # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join + # [:primary_key] + # Specify the method that returns the primary key used for the association. By default this is +id+. + # [:include] + # Specify second-order associations that should be eager loaded when this object is loaded. + # [:as] + # Specifies a polymorphic interface (See belongs_to). + # [:select] + # By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. - # * :through: Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key + # [:through] + # Specifies a Join Model through which to perform the query. Options for :class_name and :foreign_key # are ignored, as the association uses the source reflection. You can only use a :through query through a # has_one or belongs_to association on the join model. - # * :source - Specifies the source association name used by has_one :through queries. Only use it if the name cannot be + # [:source] + # Specifies the source association name used by has_one :through queries. Only use it if the name cannot be # inferred from the association. has_one :favorite, :through => :favorites will look for a # :favorite on Favorite, unless a :source is given. - # * :source_type - Specifies type of the source association used by has_one :through queries where the source + # [:source_type] + # Specifies type of the source association used by has_one :through queries where the source # association is a polymorphic +belongs_to+. - # * :readonly - If true, the associated object is readonly through the association. - # * :validate - If false, don't validate the associated object when saving the parent object. +false+ by default. - # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). + # [:readonly] + # If true, the associated object is readonly through the association. + # [:validate] + # If false, don't validate the associated object when saving the parent object. +false+ by default. + # [:accessible] + # Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_one :credit_card, :dependent => :destroy # destroys the associated credit card @@ -816,18 +896,34 @@ module ActiveRecord end end - # 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 - # belongs_to :author would add among others author.nil?. - # * association(force_reload = false) - Returns the associated object. +nil+ is returned if none is found. - # * association=(associate) - Assigns the associate object, extracts the primary key, and sets it as the foreign key. - # * association.nil? - Returns +true+ if there is no associated object. - # * build_association(attributes = {}) - Returns a new object of the associated type that has been instantiated + # Specifies a one-to-one association with another class. This method should only be used + # if this class contains the foreign key. If the other class contains the foreign key, + # then you should use +has_one+ instead. See also ActiveRecord::Associations::ClassMethods's overview + # on when to use +has_one+ and when to use +belongs_to+. + # + # Methods will be added for retrieval and query for a single associated object, for which + # this object holds an id: + # + # [association(force_reload = false)] + # Returns the associated object. +nil+ is returned if none is found. + # [association=(associate)] + # Assigns the associate object, extracts the primary key, and sets it as the foreign key. + # [association.nil?] + # Returns +true+ if there is no associated object. + # [build_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated # with +attributes+ and linked to this object through a foreign key, but has not yet been saved. - # * create_association(attributes = {}) - Returns a new object of the associated type that has been instantiated - # with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation). + # [create_association(attributes = {})] + # Returns a new object of the associated type that has been instantiated + # with +attributes+, linked to this object through a foreign key, and that + # has already been saved (if it passed the validation). + # + # (+association+ is replaced with the symbol passed as the first argument, so + # belongs_to :author would add among others author.nil?.) # - # Example: A Post class declares belongs_to :author, which will add: + # === Example + # + # A Post class declares belongs_to :author, which will add: # * Post#author (similar to Author.find(author_id)) # * Post#author=(author) (similar to post.author_id = author.id) # * Post#author? (similar to post.author == some_author) @@ -836,23 +932,30 @@ module ActiveRecord # * Post#create_author (similar to post.author = Author.new; post.author.save; post.author) # The declaration can also include an options hash to specialize the behavior of the association. # - # Options are: - # * :class_name - Specify the class name of the association. Use it only if that name can't be inferred + # === Options + # + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred # from the association name. So has_one :author will by default be linked to the Author class, but # if the real class name is Person, you'll have to specify it with this option. - # * :conditions - Specify the conditions that the associated object must meet in order to be included as a +WHERE+ + # [:conditions] + # Specify the conditions that the associated object must meet in order to be included as a +WHERE+ # SQL fragment, such as authorized = 1. - # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join + # [:select] + # By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. - # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name + # [:foreign_key] + # Specify the foreign key used for the association. By default this is guessed to be the name # of the association with an "_id" suffix. So a class that defines a belongs_to :person association will use # "person_id" as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person" # will use a foreign key of "favorite_person_id". - # * :dependent - If set to :destroy, the associated object is destroyed when this object is. If set to + # [:dependent] + # If set to :destroy, the associated object is destroyed when this object is. If set to # :delete, the associated object is deleted *without* calling its destroy method. This option should not be specified when # belongs_to is used in conjunction with a has_many relationship on another class because of the potential to leave # orphaned records behind. - # * :counter_cache - Caches the number of belonging objects on the associate class through the use of +increment_counter+ + # [:counter_cache] + # Caches the number of belonging objects on the associate class through the 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 providing @@ -860,13 +963,18 @@ module ActiveRecord # When creating a counter cache column, the database statement or migration must specify a default value of 0, failing to do # this results in a counter with +NULL+ value, which will never increment. # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+. - # * :include - Specify second-order associations that should be eager loaded when this object is loaded. - # * :polymorphic - Specify this association is a polymorphic association by passing +true+. + # [:include] + # Specify second-order associations that should be eager loaded when this object is loaded. + # [:polymorphic] + # Specify this association is a polymorphic association by passing +true+. # Note: If you've enabled the counter cache, then you may want to add the counter cache attribute # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). - # * :readonly - If true, the associated object is readonly through the association. - # * :validate - If false, don't validate the associated objects when saving the parent object. +false+ by default. - # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). + # [:readonly] + # If true, the associated object is readonly through the association. + # [:validate] + # If false, don't validate the associated objects when saving the parent object. +false+ by default. + # [:accessible] + # Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # belongs_to :firm, :foreign_key => "client_of" @@ -952,8 +1060,9 @@ module ActiveRecord configure_dependency_for_belongs_to(reflection) 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 + # Specifies a many-to-many relationship with another class. This 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 # is calculated using the < operator for String. 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 @@ -968,28 +1077,48 @@ module ActiveRecord # associations with attributes to a real join model (see introduction). # # Adds the following methods for retrieval and query: - # +collection+ is replaced with the symbol passed as the first argument, so - # has_and_belongs_to_many :categories would add among others categories.empty?. - # * collection(force_reload = false) - Returns an array of all the associated objects. + # + # [collection(force_reload = false)] + # Returns an array of all the associated objects. # An empty array is returned if none are found. - # * collection<<(object, ...) - Adds one or more objects to the collection by creating associations in the join table + # [collection<<(object, ...)] + # 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). - # * collection.delete(object, ...) - Removes one or more objects from the collection by removing their associations from the join table. + # [collection.delete(object, ...)] + # Removes one or more objects from the collection by removing their associations from the join table. # This does not destroy the objects. - # * collection=objects - Replaces the collection's content by deleting and adding objects as appropriate. - # * collection_singular_ids - Returns an array of the associated objects' ids. - # * collection_singular_ids=ids - Replace the collection by the objects identified by the primary keys in +ids+. - # * collection.clear - Removes every object from the collection. This does not destroy the objects. - # * collection.empty? - Returns +true+ if there are no associated objects. - # * collection.size - Returns the number of associated objects. - # * collection.find(id) - Finds an associated object responding to the +id+ and that + # [collection=objects] + # Replaces the collection's content by deleting and adding objects as appropriate. + # [collection_singular_ids] + # Returns an array of the associated objects' ids. + # [collection_singular_ids=ids] + # Replace the collection by the objects identified by the primary keys in +ids+. + # [collection.clear] + # Removes every object from the collection. This does not destroy the objects. + # [collection.empty?] + # Returns +true+ if there are no associated objects. + # [collection.size] + # Returns the number of associated objects. + # [collection.find(id)] + # Finds an associated object responding to the +id+ and that # meets the condition that it has to be associated with this object. - # * collection.build(attributes = {}) - Returns a new object of the collection type that has been instantiated + # Uses the same rules as ActiveRecord::Base.find. + # [collection.exist?(...)] + # Checks whether an associated object with the given conditions exists. + # Uses the same rules as ActiveRecord::Base.exists?. + # [collection.build(attributes = {})] + # 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. - # * collection.create(attributes = {}) - Returns a new object of the collection type that has been instantiated + # [collection.create(attributes = {})] + # Returns a new object of the collection type that has been instantiated # with +attributes+, linked to this object through the join table, and that has already been saved (if it passed the validation). # - # Example: A Developer class declares has_and_belongs_to_many :projects, which will add: + # (+collection+ is replaced with the symbol passed as the first argument, so + # has_and_belongs_to_many :categories would add among others categories.empty?.) + # + # === Example + # + # A Developer class declares has_and_belongs_to_many :projects, which will add: # * Developer#projects # * Developer#projects<< # * Developer#projects.delete @@ -1000,45 +1129,66 @@ module ActiveRecord # * Developer#projects.empty? # * Developer#projects.size # * Developer#projects.find(id) + # * Developer#clients.exist?(...) # * Developer#projects.build (similar to Project.new("project_id" => id)) # * Developer#projects.create (similar to c = Project.new("project_id" => id); c.save; c) # The declaration may include an options hash to specialize the behavior of the association. # - # Options are: - # * :class_name - Specify the class name of the association. Use it only if that name can't be inferred + # === Options + # + # [:class_name] + # Specify the class name of the association. Use it only if that name can't be inferred # from the association name. So has_and_belongs_to_many :projects 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. - # * :join_table - 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. - # * :foreign_key - Specify the foreign key used for the association. By default this is guessed to be the name + # [:join_table] + # 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. + # [:foreign_key] + # 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. - # * :association_foreign_key - Specify the association foreign key used for the association. By default this is + # [:association_foreign_key] + # 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. - # * :conditions - Specify the conditions that the associated object must meet in order to be included as a +WHERE+ + # [:conditions] + # Specify the conditions that the associated object must meet in order to be included as a +WHERE+ # SQL fragment, such as authorized = 1. Record creations from the association are scoped if a hash is used. # has_many :posts, :conditions => {:published => true} will create published posts with @blog.posts.create # or @blog.posts.build. - # * :order - Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, + # [:order] + # Specify the order in which the associated objects are returned as an ORDER BY SQL fragment, # such as last_name, first_name DESC - # * :uniq - If true, duplicate associated objects will be ignored by accessors and query methods. - # * :finder_sql - Overwrite the default generated SQL statement used to fetch the association with a manual statement - # * :delete_sql - Overwrite the default generated SQL statement used to remove links between the associated + # [:uniq] + # If true, duplicate associated objects will be ignored by accessors and query methods. + # [:finder_sql] + # Overwrite the default generated SQL statement used to fetch the association with a manual statement + # [:delete_sql] + # Overwrite the default generated SQL statement used to remove links between the associated # classes with a manual statement. - # * :insert_sql - Overwrite the default generated SQL statement used to add links between the associated classes + # [:insert_sql] + # Overwrite the default generated SQL statement used to add links between the associated classes # with a manual statement. - # * :extend - Anonymous module for extending the proxy, see "Association extensions". - # * :include - Specify second-order associations that should be eager loaded when the collection is loaded. - # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :limit - An integer determining the limit on the number of rows that should be returned. - # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. - # * :select - By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join + # [:extend] + # Anonymous module for extending the proxy, see "Association extensions". + # [:include] + # Specify second-order associations that should be eager loaded when the collection is loaded. + # [:group] + # An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. + # [:limit] + # An integer determining the limit on the number of rows that should be returned. + # [:offset] + # An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows. + # [:select] + # By default, this is * as in SELECT * FROM, but can be changed if, for example, you want to do a join # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. - # * :readonly - If true, all the associated objects are readonly through the association. - # * :validate - If false, don't validate the associated objects when saving the parent object. +true+ by default. - # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). + # [:readonly] + # If true, all the associated objects are readonly through the association. + # [:validate] + # If false, don't validate the associated objects when saving the parent object. +true+ by default. + # [:accessible<] + # Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_and_belongs_to_many :projects diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 4f5d72a0be..9cb64223e2 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -83,8 +83,33 @@ module ActiveRecord #:nodoc: class ReadOnlyRecord < ActiveRecordError end - # Used by Active Record transaction mechanism to distinguish rollback from other exceptional situations. - # You can use it to roll your transaction back explicitly in the block passed to +transaction+ method. + # ActiveRecord::Transactions::ClassMethods.transaction uses this exception + # to distinguish a deliberate rollback from other exceptional situations. + # Normally, raising an exception will cause the +transaction+ method to rollback + # the database transaction *and* pass on the exception. But if you raise an + # ActiveRecord::Rollback exception, then the database transaction will be rolled back, + # without passing on the exception. + # + # For example, you could do this in your controller to rollback a transaction: + # + # class BooksController < ActionController::Base + # def create + # Book.transaction do + # book = Book.new(params[:book]) + # book.save! + # if today_is_friday? + # # The system must fail on Friday so that our support department + # # won't be out of job. We silently rollback this transaction + # # without telling the user. + # raise ActiveRecord::Rollback, "Call tech support!" + # end + # end + # # ActiveRecord::Rollback is the only exception that won't be passed on + # # by ActiveRecord::Base.transaction, so this line will still be reached + # # even on Friday. + # redirect_to root_url + # end + # end class Rollback < ActiveRecordError end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 354a6c83a2..0531afbb52 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -66,12 +66,15 @@ module ActiveRecord # will happen under the protected cover of a transaction. So you can use validations to check for values that the transaction # depends on or you can raise exceptions in the callbacks to rollback. # - # == Exception handling + # == Exception handling and rolling back # # Also have in mind that exceptions thrown within a transaction block will be propagated (after triggering the ROLLBACK), so you - # should be ready to catch those in your application code. One exception is the ActiveRecord::Rollback exception, which will - # trigger a ROLLBACK when raised, but not be re-raised by the transaction block. + # should be ready to catch those in your application code. + # + # One exception is the ActiveRecord::Rollback exception, which will trigger a ROLLBACK when raised, + # but not be re-raised by the transaction block. module ClassMethods + # See ActiveRecord::Transactions::ClassMethods for detailed documentation. def transaction(&block) connection.increment_open_transactions -- cgit v1.2.3