diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index c45400d3d941e..83a9ab46c5ac5 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -9,11 +9,13 @@ def clear_aggregation_cache #:nodoc: end unless self.new_record? end - # Active Record implements aggregation through a macro-like class method called +composed_of+ for representing attributes - # as value objects. It expresses relationships like "Account [is] composed of Money [among other things]" or "Person [is] - # composed of [an] address". Each call to the macro adds a description of how the value objects are created from the - # attributes of the entity object (when the entity is initialized either as a new object or from finding an existing object) - # and how it can be turned back into attributes (when the entity is saved to the database). Example: + # Active Record implements aggregation through a macro-like class method called +composed_of+ + # for representing attributes as value objects. It expresses relationships like "Account [is] + # composed of Money [among other things]" or "Person [is] composed of [an] address". Each call + # to the macro adds a description of how the value objects are created from the attributes of + # the entity object (when the entity is initialized either as a new object or from finding an + # existing object) and how it can be turned back into attributes (when the entity is saved to + # the database). # # class Customer < ActiveRecord::Base # composed_of :balance, :class_name => "Money", :mapping => %w(balance amount) @@ -68,9 +70,10 @@ def clear_aggregation_cache #:nodoc: # end # 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 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: + # 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 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 # customer.balance # => Money value object @@ -79,8 +82,8 @@ def clear_aggregation_cache #:nodoc: # customer.balance == Money.new(20) # => true # customer.balance < Money.new(5) # => false # - # Value objects can also be composed of multiple attributes, such as the case of Address. The order of the mappings will - # determine the order of the parameters. Example: + # Value objects can also be composed of multiple attributes, such as the case of Address. The order + # of the mappings will determine the order of the parameters. # # customer.address_street = "Hyancintvej" # customer.address_city = "Copenhagen" @@ -91,38 +94,43 @@ 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 - # 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. + # 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. # - # 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#exchange_to 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 means other than the writer method. + # 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#exchange_to 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 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 ActiveSupport::FrozenObjectError. + # 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 ActiveSupport::FrozenObjectError. # - # 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 + # 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 # # == Custom constructors and converters # - # By default value objects are initialized by calling the new constructor of the value class passing each of the - # mapped attributes, in the order specified by the :mapping option, as arguments. If the value class doesn't support - # this convention then +composed_of+ allows a custom constructor to be specified. + # By default value objects are initialized by calling the new constructor of the value + # class passing each of the mapped attributes, in the order specified by the :mapping + # option, as arguments. If the value class doesn't support this convention then +composed_of+ allows + # a custom constructor to be specified. # - # When a new value is assigned to the value object the default assumption is that the new value is an instance of the value - # class. Specifying a custom converter allows the new value to be automatically converted to an instance of value class if - # necessary. + # When a new value is assigned to the value object the default assumption is that the new value + # is an instance of the value class. Specifying a custom converter allows the new value to be automatically + # converted to an instance of value class if necessary. # - # For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that should be aggregated using the - # NetAddr::CIDR value class (http://netaddr.rubyforge.org). The constructor for the value class is called +create+ and it - # expects a CIDR address string as a parameter. New values can be assigned to the value object using either another - # NetAddr::CIDR object, a string or an array. The :constructor and :converter options can be used to - # meet these requirements: + # For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that + # should be aggregated using the NetAddr::CIDR value class (http://netaddr.rubyforge.org). The constructor + # for the value class is called +create+ and it expects a CIDR address string as a parameter. New + # values can be assigned to the value object using either another NetAddr::CIDR object, a string + # or an array. The :constructor and :converter options can be used to meet + # these requirements: # # class NetworkResource < ActiveRecord::Base # composed_of :cidr, @@ -149,9 +157,9 @@ def clear_aggregation_cache #:nodoc: # # == Finding records by a value object # - # Once a +composed_of+ relationship is specified for a model, records can be loaded from the database by specifying an instance - # of the value object in the conditions hash. The following example finds all customers with +balance_amount+ equal to 20 and - # +balance_currency+ equal to "USD": + # Once a +composed_of+ relationship is specified for a model, records can be loaded from the database + # by specifying an instance of the value object in the conditions hash. The following example + # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD": # # Customer.find(:all, :conditions => {:balance => Money.new(20, "USD")}) # @@ -160,23 +168,28 @@ module ClassMethods # composed_of :address adds address and address=(new_address) methods. # # Options are: - # * :class_name - Specifies the class name of the association. Use it only if that name can't be inferred - # from the part id. So composed_of :address will by default be linked to the Address class, but - # if the real class name is CompanyAddress, you'll have to specify it with this option. - # * :mapping - Specifies the mapping of entity attributes to attributes of the value object. Each mapping - # is represented as an array where the first item is the name of the entity attribute and the second item is the - # name the attribute in the value object. The order in which mappings are defined determine the order in which - # attributes are sent to the value class constructor. + # * :class_name - Specifies the class name of the association. Use it only if that name + # can't be inferred from the part id. So composed_of :address will by default be linked + # to the Address class, but if the real class name is CompanyAddress, you'll have to specify it + # with this option. + # * :mapping - Specifies the mapping of entity attributes to attributes of the value + # object. Each mapping is represented as an array where the first item is the name of the + # entity attribute and the second item is the name the attribute in the value object. The + # order in which mappings are defined determine the order in which attributes are sent to the + # value class constructor. # * :allow_nil - Specifies that the value object will not be instantiated when all mapped - # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all mapped attributes. + # attributes are +nil+. Setting the value object to +nil+ has the effect of writing +nil+ to all + # mapped attributes. # This defaults to +false+. - # * :constructor - A symbol specifying the name of the constructor method or a Proc that is called to - # initialize the value object. The constructor is passed all of the mapped attributes, in the order that they - # are defined in the :mapping option, as arguments and uses them to instantiate a :class_name object. + # * :constructor - A symbol specifying the name of the constructor method or a Proc that + # is called to initialize the value object. The constructor is passed all of the mapped attributes, + # in the order that they are defined in the :mapping option, as arguments and uses them + # to instantiate a :class_name object. # The default is :new. - # * :converter - A symbol specifying the name of a class method of :class_name or a Proc that is - # called when a new value is assigned to the value object. The converter is passed the single value that is used - # in the assignment and is only called if the new value is not an instance of :class_name. + # * :converter - A symbol specifying the name of a class method of :class_name + # or a Proc that is called when a new value is assigned to the value object. The converter is + # passed the single value that is used in the assignment and is only called if the new value is + # not an instance of :class_name. # # Option examples: # composed_of :temperature, :mapping => %w(reading celsius) diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 08601f8ef9f6a..0f0fdc2e21c4d 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -9,8 +9,8 @@ module AssociationPreload #:nodoc: # Implements the details of eager loading of Active Record associations. # Application developers should not use this module directly. # - # ActiveRecord::Base is extended with this module. The source code in - # ActiveRecord::Base references methods defined in this module. + # ActiveRecord::Base is extended with this module. The source code in + # ActiveRecord::Base references methods defined in this module. # # Note that 'eager loading' and 'preloading' are actually the same thing. # However, there are two different eager loading strategies. @@ -55,7 +55,7 @@ module ClassMethods # == Parameters # +records+ is an array of ActiveRecord::Base. This array needs not be flat, # i.e. +records+ itself may also contain arrays of records. In any case, - # +preload_associations+ will preload the associations all records by + # +preload_associations+ will preload the all associations records by # flattening +records+. # # +associations+ specifies one or more associations that you want to @@ -110,8 +110,8 @@ def preload_associations(records, associations, preload_options={}) def preload_one_association(records, association, preload_options={}) class_to_reflection = {} # Not all records have the same class, so group then preload - # group on the reflection itself so that if various subclass share the same association then we do not split them - # unnecessarily + # group on the reflection itself so that if various subclass share the same association then + # we do not split them unnecessarily records.group_by { |record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, _records| raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection @@ -149,7 +149,8 @@ def set_association_single_records(id_to_record_map, reflection_name, associated seen_keys = {} associated_records.each do |associated_record| #this is a has_one or belongs_to: there should only be one record. - #Unfortunately we can't (in portable way) ask the database for 'all records where foo_id in (x,y,z), but please + #Unfortunately we can't (in portable way) ask the database for + #'all records where foo_id in (x,y,z), but please # only one row per distinct foo_id' so this where we enforce that next if seen_keys[associated_record[key].to_s] seen_keys[associated_record[key].to_s] = true @@ -304,7 +305,8 @@ def preload_belongs_to_association(records, reflection, preload_options={}) polymorph_type = options[:foreign_type] klasses_and_ids = {} - # Construct a mapping from klass to a list of ids to load and a mapping of those ids back to their parent_records + # Construct a mapping from klass to a list of ids to load and a mapping of those ids back + # to their parent_records records.each do |record| if klass = record.send(polymorph_type) klass_id = record.send(primary_key_name) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index fdc203e298fac..2556d243f62d8 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -114,7 +114,7 @@ module Associations # :nodoc: autoload :HasOneAssociation, 'active_record/associations/has_one_association' autoload :HasOneThroughAssociation, 'active_record/associations/has_one_through_association' - # Clears out the association cache + # Clears out the association cache. def clear_association_cache #:nodoc: self.class.reflect_on_all_associations.to_a.each do |assoc| instance_variable_set "@#{assoc.name}", nil @@ -122,7 +122,7 @@ def clear_association_cache #:nodoc: end private - # Gets the specified association instance if it responds to :loaded?, nil otherwise. + # Returns the specified association instance if it responds to :loaded?, nil otherwise. def association_instance_get(name) ivar = "@#{name}" if instance_variable_defined?(ivar) @@ -136,10 +136,12 @@ def association_instance_set(name, association) instance_variable_set("@#{name}", association) end - # 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* - # methods. Example: + # 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* + # methods. # # class Project < ActiveRecord::Base # belongs_to :portfolio @@ -148,7 +150,8 @@ def association_instance_set(name, association) # has_and_belongs_to_many :categories # end # - # The project class now has the following methods (and more) to ease the traversal and manipulation of its relationships: + # The project class now has the following methods (and more) to ease the traversal and + # manipulation of its relationships: # * Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil? # * Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?, # * Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone), @@ -159,8 +162,9 @@ def association_instance_set(name, association) # # === A word of warning # - # Don't create associations that have the same name as instance methods of ActiveRecord::Base. Since the association - # adds a method with that name to its model, it will override the inherited method and break things. + # Don't create associations that have the same name as instance methods of + # ActiveRecord::Base. Since the association adds a method with that name to + # its model, it will override the inherited method and break things. # For instance, +attributes+ and +connection+ would be bad choices for association names. # # == Auto-generated methods @@ -270,8 +274,8 @@ def association_instance_set(name, 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 - # declaring the +belongs_to+ relationship. 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. # # class User < ActiveRecord::Base # # I reference an account. @@ -300,8 +304,9 @@ def association_instance_set(name, association) # # == Unsaved objects and associations # - # You can manipulate objects and associations before they are saved to the database, but there is some special behavior you should be - # aware of, mostly involving the saving of associated objects. + # You can manipulate objects and associations before they are saved to the database, but + # there is some special behavior you should be aware of, mostly involving the saving of + # associated objects. # # You can set the :autosave option on a has_one, belongs_to, # has_many, or has_and_belongs_to_many association. Setting it @@ -310,26 +315,33 @@ def association_instance_set(name, association) # # === 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 - # 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. + # * 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 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. # # === Collections # - # * 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. + # * 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. # # === Association callbacks # - # Similar to the normal callbacks that hook into the lifecycle of an Active Record object, you can also define callbacks that get - # triggered when you add an object to or remove an object from an association collection. Example: + # Similar to the normal callbacks that hook into the lifecycle of an Active Record object, + # you can also define callbacks that get triggered when you add an object to or remove an + # object from an association collection. # # class Project # has_and_belongs_to_many :developers, :after_add => :evaluate_velocity @@ -342,19 +354,21 @@ def association_instance_set(name, association) # It's possible to stack callbacks by passing them as an array. Example: # # class Project - # has_and_belongs_to_many :developers, :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}] + # 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+. # - # 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 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: + # 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. # # class Account < ActiveRecord::Base # has_many :people do @@ -369,7 +383,8 @@ def association_instance_set(name, association) # person.first_name # => "David" # person.last_name # => "Heinemeier Hansson" # - # If you need to share the same extensions between many associations, you can use a named extension module. Example: + # If you need to share the same extensions between many associations, you can use a named + # extension module. # # module FindOrCreateByNameExtension # def find_or_create_by_name(name) @@ -386,9 +401,10 @@ def association_instance_set(name, association) # 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. - # 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: + # If you need to use multiple named extension modules, you can specify an array of modules + # with the :extend 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. # # class Account < ActiveRecord::Base # has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension] @@ -399,12 +415,14 @@ def association_instance_set(name, association) # # * +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 +has_and_belongs_to_many+ association. The advantage is that you're able to add validations, + # 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 + # +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 @@ -418,7 +436,7 @@ def association_instance_set(name, association) # end # # @author = Author.find :first - # @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to. + # @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: @@ -439,7 +457,7 @@ def association_instance_set(name, association) # # @firm = Firm.find :first # @firm.clients.collect { |c| c.invoices }.flatten # select all invoices for all clients of the firm - # @firm.invoices # selects all invoices by going through the Client join model. + # @firm.invoices # selects all invoices by going through the Client join model # # Similarly you can go through a +has_one+ association on the join model: # @@ -461,16 +479,18 @@ def association_instance_set(name, association) # @group.users.collect { |u| u.avatar }.flatten # select all avatars for all users in the group # @group.avatars # selects all avatars by going through the User join model. # - # An important caveat with going through +has_one+ or +has_many+ associations on the join model is that these associations are - # *read-only*. For example, the following would not work following the previous example: + # An important caveat with going through +has_one+ or +has_many+ associations on the + # join model is that these associations are *read-only*. For example, the following + # would not work following the previous example: # - # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around. + # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around # @group.avatars.delete(@group.avatars.last) # so would this # # === 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. + # 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. # # class Asset < ActiveRecord::Base # belongs_to :attachable, :polymorphic => true @@ -482,13 +502,16 @@ def association_instance_set(name, association) # # @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. + # 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. # - # 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. In this case, there must be a +type+ column in the posts table. + # 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. In this case, there must be a +type+ + # column in the posts table. # # class Asset < ActiveRecord::Base # belongs_to :attachable, :polymorphic => true @@ -511,9 +534,10 @@ def association_instance_set(name, association) # # == Caching # - # All of the methods are built on a simple caching principle that will keep the result of the last query around unless specifically - # instructed not to. The cache is even shared across methods to make it even cheaper to use the macro-added methods without - # worrying too much about performance at the first go. Example: + # All of the methods are built on a simple caching principle that will keep the result + # of the last query around unless specifically instructed not to. The cache is even + # shared across methods to make it even cheaper to use the macro-added methods without + # worrying too much about performance at the first go. # # project.milestones # fetches milestones from the database # project.milestones.size # uses the milestone cache @@ -523,9 +547,10 @@ def association_instance_set(name, association) # # == Eager loading of associations # - # Eager loading is a way to find objects of a certain class and a number of named associations. This is - # 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 2. Example: + # Eager loading is a way to find objects of a certain class and a number of named associations. + # This is 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 2. # # class Post < ActiveRecord::Base # belongs_to :author @@ -540,44 +565,55 @@ def association_instance_set(name, association) # puts "Last comment on: " + post.comments.first.created_on # end # - # To iterate over these one hundred posts, we'll generate 201 database queries. Let's first just optimize it for retrieving the author: + # To iterate over these one hundred posts, we'll generate 201 database queries. Let's + # first just optimize it for retrieving the author: # # for post in Post.find(:all, :include => :author) # - # This references the name of the +belongs_to+ association that also used the :author symbol. After loading the posts, find - # will collect the +author_id+ from each one and load all the referenced authors with one query. Doing so will cut down the number of queries from 201 to 102. + # This references the name of the +belongs_to+ association that also used the :author + # symbol. After loading the posts, find will collect the +author_id+ from each one and load + # all the referenced authors with one query. Doing so will cut down the number of queries + # from 201 to 102. # # We can improve upon the situation further by referencing both associations in the finder with: # # for post in Post.find(:all, :include => [ :author, :comments ]) # - # This will load all comments with a single query. This reduces the total number of queries to 3. More generally the number of queries - # will be 1 plus the number of associations named (except if some of the associations are polymorphic +belongs_to+ - see below). + # This will load all comments with a single query. This reduces the total number of queries + # to 3. More generally the number of queries will be 1 plus the number of associations + # named (except if some of the associations are polymorphic +belongs_to+ - see below). # # To include a deep hierarchy of associations, use a hash: # # for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ]) # - # That'll grab not only all the comments but all their authors and gravatar pictures. You can mix and match - # symbols, arrays and hashes in any combination to describe the associations you want to load. + # That'll grab not only all the comments but all their authors and gravatar pictures. + # You can mix and match symbols, arrays and hashes in any combination to describe the + # associations you want to load. # - # All of this power shouldn't fool you into thinking that you can pull out huge amounts of data with no performance penalty just because you've reduced - # the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no - # 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. + # All of this power shouldn't fool you into thinking that you can pull out huge amounts + # of data with no performance penalty just because you've reduced the number of queries. + # The database still needs to send all the data to Active Record and it still needs to + # be processed. So it's no 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 only one table is loaded at a time, conditions or orders cannot reference tables other than the main one. If this is the case - # Active Record falls back to the previously used LEFT OUTER JOIN based strategy. For example + # Since only one table is loaded at a time, conditions or orders cannot reference tables + # other than the main one. If this is the case Active Record falls back to the previously + # used LEFT OUTER JOIN based strategy. For example # # Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true]) # - # This will result in a single SQL query with joins along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id and - # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions like this can have unintended consequences. - # In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole - # and not just to the association. You must disambiguate column references for this fallback to happen, for example + # This will result in a single SQL query with joins along the lines of: + # LEFT OUTER JOIN comments ON comments.post_id = posts.id and + # LEFT OUTER JOIN authors ON authors.id = posts.author_id. Note that using conditions + # like this can have unintended consequences. + # In the above example posts with no approved comments are not returned at all, because + # the conditions apply to the SQL statement as a whole and not just to the association. + # You must disambiguate column references for this fallback to happen, for example # :order => "author.name DESC" will work but :order => "name DESC" will not. # - # If you do want eager load only some members of an association it is usually more natural to :include an association - # which has conditions defined on it: + # If you do want eager load only some members of an association it is usually more natural + # to :include an association which has conditions defined on it: # # class Post < ActiveRecord::Base # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true] @@ -585,9 +621,11 @@ def association_instance_set(name, association) # # Post.find(:all, :include => :approved_comments) # - # This will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved. + # This will load posts and eager load the +approved_comments+ association, which contains + # only those comments that have been approved. # - # If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects: + # If you eager load an association with a specified :limit option, it will be ignored, + # returning all the associated objects: # # class Picture < ActiveRecord::Base # has_many :most_recent_comments, :class_name => 'Comment', :order => 'id DESC', :limit => 10 @@ -595,8 +633,8 @@ def association_instance_set(name, association) # # Picture.find(:first, :include => :most_recent_comments).most_recent_comments # => returns all associated comments. # - # 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. + # 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. # # Eager loading is supported with polymorphic associations. # @@ -608,17 +646,21 @@ def association_instance_set(name, association) # # Address.find(:all, :include => :addressable) # - # This will execute one query to load the addresses and load the addressables with one query per addressable type. - # For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of - # addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback - # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent - # model's type is a column value so its corresponding table name cannot be put in the +FROM+/+JOIN+ clauses of that query. + # This will execute one query to load the addresses and load the addressables with one + # query per addressable type. + # For example if all the addressables are either of class Person or Company then a total + # of 3 queries will be executed. The list of addressable types to load is determined on + # the back of the addresses loaded. This is not supported if Active Record has to fallback + # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. + # The reason is that the parent model's type is a column value so its corresponding table + # name cannot be put in the +FROM+/+JOIN+ clauses of that query. # # == Table Aliasing # - # Active Record 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 - # for any more successive uses of the table name. + # Active Record 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 for any more successive uses of the table name. # # Post.find :all, :joins => :comments # # => SELECT ... FROM posts INNER JOIN comments ON ... @@ -651,7 +693,8 @@ def association_instance_set(name, association) # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2 # - # 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 :joins option, those table + # names will take precedence over the eager associations: # # Post.find :all, :joins => :comments, :joins => "inner join comments ..." # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ... @@ -660,7 +703,8 @@ def association_instance_set(name, association) # INNER JOIN comments special_comments_posts ... # INNER JOIN comments ... # - # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database. + # Table aliases are automatically truncated according to the maximum length of table identifiers + # according to the specific database. # # == Modules # @@ -676,9 +720,10 @@ def association_instance_set(name, association) # end # end # - # When Firm#clients is called, it will in turn call MyApplication::Business::Client.find_all_by_firm_id(firm.id). - # If you want to associate with a class in another module scope, this can be done by specifying the complete class name. - # Example: + # When Firm#clients is called, it will in turn call + # MyApplication::Business::Client.find_all_by_firm_id(firm.id). + # If you want to associate with a class in another module scope, this can be done by + # specifying the complete class name. # # module MyApplication # module Business @@ -694,8 +739,8 @@ def association_instance_set(name, association) # # == Bi-directional associations # - # When you specify an association there is usually an association on the associated model that specifies the same - # relationship in reverse. For example, with the following models: + # When you specify an association there is usually an association on the associated model + # that specifies the same relationship in reverse. For example, with the following models: # # class Dungeon < ActiveRecord::Base # has_many :traps @@ -710,9 +755,11 @@ def association_instance_set(name, association) # belongs_to :dungeon # end # - # The +traps+ association on +Dungeon+ and the the +dungeon+ association on +Trap+ are the inverse of each other and the - # inverse of the +dungeon+ association on +EvilWizard+ is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default, - # Active Record doesn't know anything about these inverse relationships and so no object loading optimisation is possible. For example: + # The +traps+ association on +Dungeon+ and the the +dungeon+ association on +Trap+ are + # the inverse of each other and the inverse of the +dungeon+ association on +EvilWizard+ + # is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default, + # Active Record doesn't know anything about these inverse relationships and so no object + # loading optimisation is possible. For example: # # d = Dungeon.first # t = d.traps.first @@ -720,9 +767,11 @@ def association_instance_set(name, association) # d.level = 10 # d.level == t.dungeon.level # => false # - # The +Dungeon+ instances +d+ and t.dungeon in the above example refer to the same object data from the database, but are - # actually different in-memory copies of that data. Specifying the :inverse_of option on associations lets you tell - # Active Record about inverse relationships and it will optimise object loading. For example, if we changed our model definitions to: + # The +Dungeon+ instances +d+ and t.dungeon in the above example refer to + # the same object data from the database, but are actually different in-memory copies + # of that data. Specifying the :inverse_of option on associations lets you tell + # Active Record about inverse relationships and it will optimise object loading. For + # example, if we changed our model definitions to: # # class Dungeon < ActiveRecord::Base # has_many :traps, :inverse_of => :dungeon @@ -737,8 +786,8 @@ def association_instance_set(name, association) # belongs_to :dungeon, :inverse_of => :evil_wizard # end # - # Then, from our code snippet above, +d+ and t.dungeon are actually the same in-memory instance and our final d.level == t.dungeon.level - # will return +true+. + # Then, from our code snippet above, +d+ and t.dungeon are actually the same + # in-memory instance and our final d.level == t.dungeon.level will return +true+. # # There are limitations to :inverse_of support: # @@ -748,13 +797,13 @@ def association_instance_set(name, association) # # == Type safety with ActiveRecord::AssociationTypeMismatch # - # If you attempt to assign an object to an association that doesn't match the inferred or specified :class_name, you'll - # get an ActiveRecord::AssociationTypeMismatch. + # If you attempt to assign an object to an association that doesn't match the inferred + # or specified :class_name, you'll get an ActiveRecord::AssociationTypeMismatch. # # == Options # - # All of the association macros can be specialized through options. This makes cases more complex than the simple and guessable ones - # possible. + # All of the association macros can be specialized through options. This makes cases + # more complex than the simple and guessable ones possible. module ClassMethods # Specifies a one-to-many association. The following methods for retrieval and query of # collections of associated objects will be added: @@ -828,20 +877,22 @@ module ClassMethods # === 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. + # 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+ - # 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. + # 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, # 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 - # 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. + # 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] @@ -855,10 +906,12 @@ module ClassMethods # # [: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. + # 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 - # specified but not :counter_sql, :counter_sql will be generated by replacing SELECT ... FROM with SELECT COUNT(*) FROM. + # 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] @@ -866,25 +919,31 @@ module ClassMethods # [:group] # An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. # [:having] - # Combined with +:group+ this can be used to filter the records that a GROUP BY returns. Uses the HAVING SQL-clause. + # Combined with +:group+ this can be used to filter the records that a GROUP BY + # returns. Uses the HAVING 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. + # 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. + # 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 - # are ignored, as the association uses the source reflection. You can only use a :through query through a belongs_to - # has_one or has_many association on the join model. The collection of join models can be managed via the collection - # API. For example, new join models are created for newly associated objects, and if some are gone their rows are deleted (directly, + # 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, has_one + # or has_many association on the join model. The collection of join models + # can be managed via the collection API. For example, new join models are created for + # newly associated objects, and if some are gone their rows are deleted (directly, # no destroy callbacks are triggered). # [: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 + # 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 @@ -896,12 +955,14 @@ module ClassMethods # [:validate] # If false, don't validate the associated objects when saving the parent object. true by default. # [:autosave] - # If true, always save the associated objects or destroy them if marked for destruction, when saving the parent object. + # If true, always save the associated objects or destroy them if marked for destruction, + # when saving the parent object. # If false, never save or destroy the associated objects. # By default, only save associated objects that are new records. # [:inverse_of] - # Specifies the name of the belongs_to association on the associated object that is the inverse of this has_many - # association. Does not work in combination with :through or :as options. + # Specifies the name of the belongs_to association on the associated object + # that is the inverse of this has_many association. Does not work in combination + # with :through or :as options. # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. # # Option examples: @@ -975,19 +1036,20 @@ def has_many(association_id, options = {}, &extension) # [:conditions] # Specify the conditions that the associated object must meet in order to be included as a +WHERE+ # SQL fragment, such as rank = 5. Record creation from the association is scoped if a hash - # is used. has_one :account, :conditions => {:enabled => true} will create an enabled account with @company.create_account - # or @company.build_account. + # is used. has_one :account, :conditions => {:enabled => true} will create + # an enabled account with @company.create_account or @company.build_account. # [: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 - # :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. + # :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 - # 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. # [:primary_key] # Specify the method that returns the primary key used for the association. By default this is +id+. # [:include] @@ -995,15 +1057,18 @@ def has_many(association_id, options = {}, &extension) # [: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. + # 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 - # 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. + # 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 - # inferred from the association. has_one :favorite, :through => :favorites will look for a + # 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 @@ -1013,17 +1078,19 @@ def has_many(association_id, options = {}, &extension) # [:validate] # If false, don't validate the associated object when saving the parent object. +false+ by default. # [:autosave] - # If true, always save the associated object or destroy it if marked for destruction, when saving the parent object. - # If false, never save or destroy the associated object. + # If true, always save the associated object or destroy it if marked for destruction, + # when saving the parent object. If false, never save or destroy the associated object. # By default, only save the associated object if it's a new record. # [:inverse_of] - # Specifies the name of the belongs_to association on the associated object that is the inverse of this has_one - # association. Does not work in combination with :through or :as options. + # Specifies the name of the belongs_to association on the associated object + # that is the inverse of this has_one association. Does not work in combination + # with :through or :as options. # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. # # Option examples: # has_one :credit_card, :dependent => :destroy # destroys the associated credit card - # has_one :credit_card, :dependent => :nullify # updates the associated records foreign key value to NULL rather than destroying it + # has_one :credit_card, :dependent => :nullify # updates the associated records foreign + # # key value to NULL rather than destroying it # has_one :last_comment, :class_name => "Comment", :order => "posted_on" # has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'" # has_one :attachment, :as => :attachable @@ -1085,27 +1152,34 @@ def has_one(association_id, options = {}) # 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 - # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. + # 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 - # 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". + # 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". # [:primary_key] - # Specify the method that returns the primary key of associated object used for the association. By default this is id. + # Specify the method that returns the primary key of associated object used for the association. + # By default this is id. # [: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 + # :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+ - # 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 - # a column name instead of a +true+/+false+ value to this option (e.g., :counter_cache => :my_custom_counter.) - # Note: Specifying a counter cache will add it to that model's list of readonly attributes using +attr_readonly+. + # 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 a column name instead of a +true+/+false+ value to this + # option (e.g., :counter_cache => :my_custom_counter.) + # 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] @@ -1117,15 +1191,18 @@ def has_one(association_id, options = {}) # [:validate] # If false, don't validate the associated objects when saving the parent object. +false+ by default. # [:autosave] - # If true, always save the associated object or destroy it if marked for destruction, when saving the parent object. + # If true, always save the associated object or destroy it if marked for destruction, when + # saving the parent object. # If false, never save or destroy the associated object. # By default, only save the associated object if it's a new record. # [:touch] - # If true, the associated object will be touched (the updated_at/on attributes set to now) when this record is either saved or - # destroyed. If you specify a symbol, that attribute will be updated with the current time instead of the updated_at/on attribute. + # If true, the associated object will be touched (the updated_at/on attributes set to now) + # when this record is either saved or destroyed. If you specify a symbol, that attribute + # will be updated with the current time instead of the updated_at/on attribute. # [:inverse_of] - # Specifies the name of the has_one or has_many association on the associated object that is the inverse of this belongs_to - # association. Does not work in combination with the :polymorphic options. + # Specifies the name of the has_one or has_many association on the associated + # object that is the inverse of this belongs_to association. Does not work in + # combination with the :polymorphic options. # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail. # # Option examples: @@ -1159,9 +1236,10 @@ def belongs_to(association_id, options = {}) # 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 + # 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 # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the @@ -1183,9 +1261,10 @@ def belongs_to(association_id, options = {}) # end # end # - # 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 attributes). It's strongly recommended that you upgrade any + # 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 attributes). 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: @@ -1225,7 +1304,8 @@ def belongs_to(association_id, options = {}) # 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 - # with +attributes+, 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). # # (+collection+ is replaced with the symbol passed as the first argument, so # has_and_belongs_to_many :categories would add among others categories.empty?.) @@ -1260,8 +1340,9 @@ def belongs_to(association_id, options = {}) # 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 - # to Project 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 to Project will use "person_id" as the + # default :foreign_key. # [:association_foreign_key] # Specify the foreign key used for the association on the receiving side of the association. # By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed. @@ -1269,7 +1350,8 @@ def belongs_to(association_id, options = {}) # the 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+ - # SQL fragment, such as authorized = 1. Record creations from the association are scoped if a hash is used. + # 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] @@ -1281,7 +1363,8 @@ def belongs_to(association_id, options = {}) # Overwrite the default generated SQL statement used to fetch the association with a manual statement # [: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. + # specified but not :counter_sql, :counter_sql will be generated by + # replacing SELECT ... FROM with SELECT COUNT(*) FROM. # [:delete_sql] # Overwrite the default generated SQL statement used to remove links between the associated # classes with a manual statement. @@ -1295,20 +1378,24 @@ def belongs_to(association_id, options = {}) # [:group] # An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. # [:having] - # Combined with +:group+ this can be used to filter the records that a GROUP BY returns. Uses the HAVING SQL-clause. + # Combined with +:group+ this can be used to filter the records that a GROUP BY returns. + # Uses the HAVING 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. + # 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. + # 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. # [:autosave] - # If true, always save the associated objects or destroy them if marked for destruction, when saving the parent object. + # If true, always save the associated objects or destroy them if marked for destruction, when + # saving the parent object. # If false, never save or destroy the associated objects. # By default, only save associated objects that are new records. # diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb index e61af93d1ea4f..bec123e7a259a 100644 --- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb @@ -106,9 +106,10 @@ def construct_scope :limit => @reflection.options[:limit] } } end - # Join tables with additional columns on top of the two foreign keys must be considered ambiguous unless a select - # 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. + # Join tables with additional columns on top of the two foreign keys must be considered + # ambiguous unless a select 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_ambiguous_select?(select_clause) !select_clause && columns.size != 2 end diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb index 17f850756f805..608b1c741ad79 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -24,9 +24,10 @@ def destroy(*records) end end - # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and - # calling collection.size if it has. If it's more likely than not that the collection does have a size larger than zero, - # and you need to fetch that collection afterwards, it'll take one fewer SELECT query if you use #length. + # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been + # loaded and calling collection.size if it has. If it's more likely than not that the collection does + # have a size larger than zero, and you need to fetch that collection afterwards, it'll take one fewer + # SELECT query if you use #length. def size return @owner.send(:read_attribute, cached_counter_attribute_name) if has_cached_counter? return @target.size if loaded? diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb index 783d61383bec0..8f0aacba42967 100644 --- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb +++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb @@ -14,7 +14,8 @@ module TimeZoneConversion module ClassMethods protected # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled. - # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone. + # This enhanced read method automatically converts the UTC time stored in the database to the time + # zone stored in Time.zone. def define_method_attribute(attr_name) if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name]) method_body, line = <<-EOV, __LINE__ + 1 diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index e31acac05041b..7a2de3bf80913 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -14,8 +14,8 @@ def define_method_attribute=(attr_name) end end - # Updates the attribute identified by attr_name with the specified +value+. Empty strings for fixnum and float - # columns are turned into +nil+. + # Updates the attribute identified by attr_name with the specified +value+. Empty strings + # for fixnum and float columns are turned into +nil+. def write_attribute(attr_name, value) attr_name = attr_name.to_s attr_name = self.class.primary_key if attr_name == 'id' diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index 062b010436057..2c7afe3c9fb74 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -4,14 +4,13 @@ module ActiveRecord # = Active Record Autosave Association # # AutosaveAssociation is a module that takes care of automatically saving - # your associations when the parent is saved. In addition to saving, it - # also destroys any associations that were marked for destruction. + # associacted records when parent is saved. In addition to saving, it + # also destroys any associated records that were marked for destruction. # (See mark_for_destruction and marked_for_destruction?) # # Saving of the parent, its associations, and the destruction of marked # associations, all happen inside 1 transaction. This should never leave the - # database in an inconsistent state after, for instance, mass assigning - # attributes and saving them. + # database in an inconsistent state. # # If validations for any of the associations fail, their error messages will # be applied to the parent. @@ -21,8 +20,6 @@ module ActiveRecord # # === One-to-one Example # - # Consider a Post model with one Author: - # # class Post # has_one :author, :autosave => true # end @@ -155,11 +152,12 @@ def #{type}(name, options = {}) CODE end - # Adds a validate and save callback for the association as specified by + # Adds validation and save callbacks for the association as specified by # the +reflection+. # - # For performance reasons, we don't check whether to validate at runtime, - # but instead only define the method and callback when needed. However, + # For performance reasons, we don't check whether to validate at runtime. + # However the validation and callback methods are lazy and those methods + # get created when they are invoked for the very first time. However, # this can change, for instance, when using nested attributes, which is # called _after_ the association has been defined. Since we don't want # the callbacks to get defined multiple times, there are guards that @@ -197,14 +195,15 @@ def add_autosave_association_callbacks(reflection) end end - # Reloads the attributes of the object as usual and removes a mark for destruction. + # Reloads the attributes of the object as usual and clears marked_for_destruction flag. def reload(options = nil) @marked_for_destruction = false super end # Marks this record to be destroyed as part of the parents save transaction. - # This does _not_ actually destroy the record yet, rather it will be destroyed when parent.save is called. + # This does _not_ actually destroy the record instantly, rather child record will be destroyed + # when parent.save is called. # # Only useful if the :autosave option on the parent is enabled for this associated model. def mark_for_destruction @@ -249,7 +248,7 @@ def nested_records_changed_for_autosave? end # Validate the association if :validate or :autosave is - # turned on for the association specified by +reflection+. + # turned on for the association. def validate_single_association(reflection) if (association = association_instance_get(reflection.name)) && !association.target.nil? association_valid?(reflection, association) @@ -357,14 +356,9 @@ def save_has_one_association(reflection) end end - # Saves the associated record if it's new or :autosave is enabled - # on the association. - # - # In addition, it will destroy the association if it was marked for - # destruction with mark_for_destruction. + # Saves the associated record if it's new or :autosave is enabled. # - # This all happens inside a transaction, _if_ the Transactions module is included into - # ActiveRecord::Base after the AutosaveAssociation module, which it does by default. + # In addition, it will destroy the association if it was marked for destruction. def save_belongs_to_association(reflection) if (association = association_instance_get(reflection.name)) && !association.destroyed? autosave = reflection.options[:autosave] @@ -384,4 +378,4 @@ def save_belongs_to_association(reflection) end end end -end \ No newline at end of file +end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 391c287fe4627..12736d3d5ba94 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -26,17 +26,19 @@ module ActiveRecord #:nodoc: # = Active Record # - # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with - # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change - # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain + # Active Record objects don't specify their attributes directly, but rather infer them from + # the table definition with which they're linked. Adding, removing, and changing attributes + # and their type is done directly in the database. Any change is instantly reflected in the + # Active Record objects. The mapping that binds a given Active Record class to a certain # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones. # # See the mapping rules in table_name and the full example in link:files/README.html for more insight. # # == Creation # - # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when - # you're receiving the data from somewhere else, like an HTTP request. It works like this: + # Active Records accept constructor parameters either in a hash or as a block. The hash + # method is especially useful when you're receiving the data from somewhere else, like an + # HTTP request. It works like this: # # user = User.new(:name => "David", :occupation => "Code Artist") # user.name # => "David" @@ -75,14 +77,17 @@ module ActiveRecord #:nodoc: # end # end # - # The authenticate_unsafely method inserts the parameters directly into the query and is thus susceptible to SQL-injection - # attacks if the user_name and +password+ parameters come directly from an HTTP request. The authenticate_safely and - # authenticate_safely_simply both will sanitize the user_name and +password+ before inserting them in the query, - # which will ensure that an attacker can't escape the query and fake the login (or worse). + # The authenticate_unsafely method inserts the parameters directly into the query + # and is thus susceptible to SQL-injection attacks if the user_name and +password+ + # parameters come directly from an HTTP request. The authenticate_safely and + # authenticate_safely_simply both will sanitize the user_name and +password+ + # before inserting them in the query, which will ensure that an attacker can't escape the + # query and fake the login (or worse). # - # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth - # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing - # the question marks with symbols and supplying a hash with values for the matching symbol keys: + # When using multiple parameters in the conditions, it can easily become hard to read exactly + # what the fourth or fifth question mark is supposed to represent. In those cases, you can + # resort to named bind variables instead. That's done by replacing the question marks with + # symbols and supplying a hash with values for the matching symbol keys: # # Company.where( # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date", @@ -103,18 +108,19 @@ module ActiveRecord #:nodoc: # # Student.where(:grade => [9,11,12]) # - # When joining tables, nested hashes or keys written in the form 'table_name.column_name' can be used to qualify the table name of a - # particular condition. For instance: + # When joining tables, nested hashes or keys written in the form 'table_name.column_name' + # can be used to qualify the table name of a particular condition. For instance: # # Student.joins(:schools).where(:schools => { :type => 'public' }) # Student.joins(:schools).where('schools.type' => 'public' ) # # == Overwriting default accessors # - # All column values are automatically available through basic accessors on the Active Record object, but sometimes you - # want to specialize this behavior. This can be done by overwriting the default accessors (using the same - # name as the attribute) and calling read_attribute(attr_name) and write_attribute(attr_name, value) to actually change things. - # Example: + # All column values are automatically available through basic accessors on the Active Record + # object, but sometimes you want to specialize this behavior. This can be done by overwriting + # the default accessors (using the same name as the attribute) and calling + # read_attribute(attr_name) and write_attribute(attr_name, value) to actually + # change things. # # class Song < ActiveRecord::Base # # Uses an integer of seconds to hold the length of the song @@ -128,8 +134,8 @@ module ActiveRecord #:nodoc: # end # end # - # You can alternatively use self[:attribute]=(value) and self[:attribute] instead of write_attribute(:attribute, value) and - # read_attribute(:attribute) as a shorter form. + # You can alternatively use self[:attribute]=(value) and self[:attribute] + # instead of write_attribute(:attribute, value) and read_attribute(:attribute). # # == Attribute query methods # @@ -147,34 +153,43 @@ module ActiveRecord #:nodoc: # # == Accessing attributes before they have been typecasted # - # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. - # That can be done by using the _before_type_cast accessors that all attributes have. For example, if your Account model - # has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast. + # Sometimes you want to be able to read the raw attribute data without having the column-determined + # typecast run its course first. That can be done by using the _before_type_cast + # accessors that all attributes have. For example, if your Account model has a balance attribute, + # you can call account.balance_before_type_cast or account.id_before_type_cast. # - # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display - # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you - # want. + # This is especially useful in validation situations where the user might supply a string for an + # integer field and you want to display the original string back in an error message. Accessing the + # attribute normally would typecast the string to 0, which isn't what you want. # # == Dynamic attribute-based finders # - # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by - # appending the name of an attribute to find_by_, find_last_by_, or find_all_by_, so you get finders like Person.find_by_user_name, - # Person.find_all_by_last_name, and Payment.find_by_transaction_id. So instead of writing + # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects + # by simple queries without turning to SQL. They work by appending the name of an attribute + # to find_by_, find_last_by_, or find_all_by_ and thus produces finders + # like Person.find_by_user_name, Person.find_all_by_last_name, and + # Payment.find_by_transaction_id. Instead of writing # Person.where(:user_name => user_name).first, you just do Person.find_by_user_name(user_name). - # And instead of writing Person.where(:last_name => last_name).all, you just do Person.find_all_by_last_name(last_name). + # And instead of writing Person.where(:last_name => last_name).all, you just do + # Person.find_all_by_last_name(last_name). # - # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like - # Person.find_by_user_name_and_password or even Payment.find_by_purchaser_and_state_and_country. So instead of writing - # Person.where(:user_name => user_name, :password => password).first, you just do - # Person.find_by_user_name_and_password(user_name, password). + # It's also possible to use multiple attributes in the same find by separating them with "_and_". + # + # Person.where(:user_name => user_name, :password => password).first + # Person.find_by_user_name_and_password #with dynamic finder + # + # Person.where(:user_name => user_name, :password => password, :gender => 'male').first + # Payment.find_by_user_name_and_password_and_gender # - # It's even possible to call these dynamic finder methods on relations and named scopes. For example : + # It's even possible to call these dynamic finder methods on relations and named scopes. # # Payment.order("created_on").find_all_by_amount(50) # Payment.pending.find_last_by_amount(100) # - # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with - # find_or_create_by_ and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example: + # The same dynamic finder style can be used to create the object if it doesn't already exist. + # This dynamic finder is called with find_or_create_by_ and will return the object if + # it already exists and otherwise creates it, then returns it. Protected attributes won't be set + # unless they are given in a block. # # # No 'Summer' tag exists # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer") @@ -185,23 +200,33 @@ module ActiveRecord #:nodoc: # # Now 'Bob' exist and is an 'admin' # User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true } # - # Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won't be set unless they are given in a block. For example: + # Use the find_or_initialize_by_ finder if you want to return a new record without + # saving it first. Protected attributes won't be set unless they are given in a block. # # # No 'Winter' tag exists # winter = Tag.find_or_initialize_by_name("Winter") # winter.new_record? # true # # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of - # a list of parameters. For example: + # a list of parameters. # # Tag.find_or_create_by_name(:name => "rails", :creator => current_user) # - # That will either find an existing tag named "rails", or create a new one while setting the user that created it. + # That will either find an existing tag named "rails", or create a new one while setting the + # user that created it. + # + # Just like find_by_*, you can also use scoped_by_* to retrieve data. The good thing about + # using this feature is that the very first time result is returned using method_missing technique + # but after that the method is declared on the class. Henceforth method_missing will not be hit. + # + # User.scoped_by_user_name('David') # # == Saving arrays, hashes, and other non-mappable objects in text columns # - # Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method +serialize+. - # This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example: + # Active Record can serialize any object in text columns using YAML. To do so, you must + # specify this with a call to the class method +serialize+. + # This makes it possible to store arrays, hashes, and other non-mappable objects without doing + # any additional work. # # class User < ActiveRecord::Base # serialize :preferences @@ -210,8 +235,8 @@ module ActiveRecord #:nodoc: # user = User.create(:preferences => { "background" => "black", "display" => large }) # User.find(user.id).preferences # => { "background" => "black", "display" => large } # - # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a - # descendant of a class not in the hierarchy. Example: + # You can also specify a class option as the second parameter that'll raise an exception + # if a serialized object is retrieved as a descendant of a class not in the hierarchy. # # class User < ActiveRecord::Base # serialize :preferences, Hash @@ -222,52 +247,63 @@ module ActiveRecord #:nodoc: # # == Single table inheritance # - # Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed - # by overwriting Base.inheritance_column). This means that an inheritance looking like this: + # Active Record allows inheritance by storing the name of the class in a column that by + # default is named "type" (can be changed by overwriting Base.inheritance_column). + # This means that an inheritance looking like this: # # class Company < ActiveRecord::Base; end # class Firm < Company; end # class Client < Company; end # class PriorityClient < Client; end # - # When you do Firm.create(:name => "37signals"), this record will be saved in the companies table with type = "Firm". You can then - # fetch this row again using Company.where(:name => '37signals').first and it will return a Firm object. + # When you do Firm.create(:name => "37signals"), this record will be saved in + # the companies table with type = "Firm". You can then fetch this row again using + # Company.where(:name => '37signals').first and it will return a Firm object. # - # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just - # like normal subclasses with no special magic for differentiating between them or reloading the right type with find. + # If you don't have a type column defined in your table, single-table inheritance won't + # be triggered. In that case, it'll work just like normal subclasses with no special magic + # for differentiating between them or reloading the right type with find. # # Note, all the attributes for all the cases are kept in the same table. Read more: # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html # # == Connection to multiple databases in different models # - # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection. - # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection. - # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection + # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved + # by ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this + # connection. But you can also set a class-specific connection. For example, if Course is an + # ActiveRecord::Base, but resides in a different database, you can just say Course.establish_connection # and Course and all of its subclasses will use this connection instead. # - # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is - # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool. + # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is + # a Hash indexed by the class. If a connection is requested, the retrieve_connection method + # will go up the class-hierarchy until a connection is found in the connection pool. # # == Exceptions # # * ActiveRecordError - Generic error class and superclass of all other errors raised by Active Record. # * AdapterNotSpecified - The configuration hash used in establish_connection didn't include an # :adapter key. - # * AdapterNotFound - The :adapter key used in establish_connection specified a non-existent adapter + # * AdapterNotFound - The :adapter key used in establish_connection specified a + # non-existent adapter # (or a bad spelling of an existing one). - # * AssociationTypeMismatch - The object assigned to the association wasn't of the type specified in the association definition. + # * AssociationTypeMismatch - The object assigned to the association wasn't of the type + # specified in the association definition. # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter. - # * ConnectionNotEstablished+ - No connection has been established. Use establish_connection before querying. + # * ConnectionNotEstablished+ - No connection has been established. Use establish_connection + # before querying. # * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist # or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal # nothing was found, please check its documentation for further details. # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message. # * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the - # attributes= method. The +errors+ property of this exception contains an array of AttributeAssignmentError + # attributes= method. The +errors+ property of this exception contains an array of + # AttributeAssignmentError # objects that should be inspected to determine which attributes triggered the errors. - # * AttributeAssignmentError - An error occurred while doing a mass assignment through the attributes= method. - # You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error. + # * AttributeAssignmentError - An error occurred while doing a mass assignment through the + # attributes= method. + # You can inspect the +attribute+ property of the exception object to determine which attribute + # triggered the error. # # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level). # So it's possible to assign a logger to the class through Base.logger= which will then be used by all @@ -275,8 +311,9 @@ module ActiveRecord #:nodoc: class Base ## # :singleton-method: - # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed - # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+. + # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, + # which is then passed on to any new database connections made and which can be retrieved on both + # a class and instance level by calling +logger+. cattr_accessor :logger, :instance_writer => false class << self @@ -323,21 +360,24 @@ def subclasses ## # :singleton-method: - # Accessor for the prefix type that will be prepended to every primary key column name. The options are :table_name and - # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as - # the primary column. If the latter is specified, the Product class will look for "product_id" instead of "id". Remember + # Accessor for the prefix type that will be prepended to every primary key column name. + # The options are :table_name and :table_name_with_underscore. If the first is specified, + # the Product class will look for "productid" instead of "id" as the primary column. If the + # latter is specified, the Product class will look for "product_id" instead of "id". Remember # that this is a global setting for all Active Records. cattr_accessor :primary_key_prefix_type, :instance_writer => false @@primary_key_prefix_type = nil ## # :singleton-method: - # Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all - # table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace - # for tables in a shared database. By default, the prefix is the empty string. + # Accessor for the name of the prefix string to prepend to every table name. So if set + # to "basecamp_", all table names will be named like "basecamp_projects", "basecamp_people", + # etc. This is a convenient way of creating a namespace for tables in a shared database. + # By default, the prefix is the empty string. # - # If you are organising your models within modules you can add a prefix to the models within a namespace by defining - # a singleton method in the parent module called table_name_prefix which returns your chosen prefix. + # If you are organising your models within modules you can add a prefix to the models within + # a namespace by defining a singleton method in the parent module called table_name_prefix which + # returns your chosen prefix. class_attribute :table_name_prefix, :instance_writer => false self.table_name_prefix = "" @@ -358,8 +398,8 @@ def subclasses ## # :singleton-method: - # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database. - # This is set to :local by default. + # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling + # dates and times from the database. This is set to :local by default. cattr_accessor :default_timezone, :instance_writer => false @@default_timezone = :local @@ -505,15 +545,18 @@ def serialize(attr_name, class_name = Object) serialized_attributes[attr_name.to_s] = class_name end - # Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values. + # Returns a hash of all the attributes that have been specified for serialization as + # keys and their class restriction as values. def serialized_attributes read_inheritable_attribute(:attr_serialized) or write_inheritable_attribute(:attr_serialized, {}) end - # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending - # directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used - # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class - # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb. + # Guesses the table name (in forced lower-case) based on the name of the class in the + # inheritance hierarchy descending directly from ActiveRecord::Base. So if the hierarchy + # looks like: Reply < Message < ActiveRecord::Base, then Message is used + # to guess the table name even when called on Reply. The rules used to do the guess + # are handled by the Inflector class in Active Support, which knows almost all common + # English inflections. You can add new inflections in config/initializers/inflections.rb. # # Nested classes are given table names prefixed by the singular form of # the parent's table name. Enclosing modules are not considered. @@ -923,15 +966,15 @@ def compute_table_name end end - # Enables dynamic finders like find_by_user_name(user_name) and find_by_user_name_and_password(user_name, password) - # that are turned into where(:user_name => user_name).first and where(:user_name => user_name, :password => :password).first - # respectively. Also works for all by using find_all_by_amount(50) that is turned into where(:amount => 50).all. + # Enables dynamic finders like User.find_by_user_name(user_name) and + # User.scoped_by_user_name(user_name). Refer to Dynamic attribute-based finders + # section at the top of this file for more detailed information. # - # It's even possible to use all the additional parameters to +find+. For example, the full interface for +find_all_by_amount+ - # is actually find_all_by_amount(amount, options). + # It's even possible to use all the additional parameters to +find+. For example, the + # full interface for +find_all_by_amount+ is actually find_all_by_amount(amount, options). # - # Each dynamic finder, scope or initializer/creator is also defined in the class after it is first invoked, so that future - # attempts to use it do not run through method_missing. + # Each dynamic finder using scoped_by_* is also defined in the class after it + # is first invoked, so that future attempts to use it do not run through method_missing. def method_missing(method_id, *arguments, &block) if match = DynamicFinderMatch.match(method_id) attribute_names = match.attribute_names @@ -1607,10 +1650,11 @@ def clone_attribute_value(reader_method, attribute_name) private - # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendant. - # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to - # set Reply[Reply.inheritance_column] = "Reply" yourself. No such attribute would be set for objects of the - # Message class in that example. + # Sets the attribute used for single table inheritance to this class name if this is not the + # ActiveRecord::Base descendant. + # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to + # do Reply.new without having to set Reply[Reply.inheritance_column] = "Reply" yourself. + # No such attribute would be set for objects of the Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? write_attribute(self.class.inheritance_column, self.class.sti_name) @@ -1659,8 +1703,9 @@ def interpolate_sql(sql, record = nil) # by calling new on the column type or aggregation type (through composed_of) object with these parameters. # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the - # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float, - # s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil. + # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, + # f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the + # attribute will be set to nil. def assign_multiparameter_attributes(pairs) execute_callstack_for_multiparameter_attributes( extract_callstack_for_multiparameter_attributes(pairs) diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 82c45a41b0d11..7f10fbf8b012e 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -26,8 +26,8 @@ module ActiveRecord # after_rollback. # # That's a total of ten callbacks, which gives you immense power to react and prepare for each state in the - # Active Record lifecycle. The sequence for calling Base#save for an existing record is similar, except that each - # _on_create callback is replaced by the corresponding _on_update callback. + # Active Record lifecycle. The sequence for calling Base#save for an existing record is similar, + # except that each _on_create callback is replaced by the corresponding _on_update callback. # # Examples: # class CreditCard < ActiveRecord::Base @@ -55,9 +55,9 @@ module ActiveRecord # # == Inheritable callback queues # - # Besides the overwritable callback methods, it's also possible to register callbacks through the use of the callback macros. - # Their main advantage is that the macros add behavior into a callback queue that is kept intact down through an inheritance - # hierarchy. Example: + # Besides the overwritable callback methods, it's also possible to register callbacks through the + # use of the callback macros. Their main advantage is that the macros add behavior into a callback + # queue that is kept intact down through an inheritance hierarchy. # # class Topic < ActiveRecord::Base # before_destroy :destroy_author @@ -67,9 +67,9 @@ 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+ are called. Contrast this to the situation where we've implemented the save behavior through overwriteable - # methods: + # Now, when Topic#destroy is run only +destroy_author+ is called. When Reply#destroy 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 # def before_destroy() destroy_author end @@ -79,20 +79,21 @@ 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 use the regular overwriteable methods - # when you want to leave it up to each descendant to decide whether they want to call +super+ and trigger the inherited callbacks. + # 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 use the regular overwriteable methods when you want to leave it up to each descendant + # 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 - # be inherited. + # *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 be inherited. # # == Types of callbacks # # There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects, - # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects are the - # recommended approaches, inline methods using a proc are sometimes appropriate (such as for creating mix-ins), and inline - # eval methods are deprecated. + # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects + # are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for + # creating mix-ins), and inline eval methods are deprecated. # # The method reference callbacks work by specifying a protected or private method available in the object, like this: # @@ -169,15 +170,15 @@ module ActiveRecord # end # end # - # The callback macros usually accept a symbol for the method they're supposed to run, but you can also pass a "method string", - # which will then be evaluated within the binding of the callback. Example: + # The callback macros usually accept a symbol for the method they're supposed to run, but you can also + # pass a "method string", which will then be evaluated within the binding of the callback. Example: # # class Topic < ActiveRecord::Base # before_destroy 'self.class.delete_all "parent_id = #{id}"' # end # - # Notice that single quotes (') are used so the #{id} part isn't evaluated until the callback is triggered. Also note that these - # inline callbacks can be stacked just like the regular ones: + # Notice that single quotes (') are used so the #{id} 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 # before_destroy 'self.class.delete_all "parent_id = #{id}"', @@ -186,22 +187,24 @@ module ActiveRecord # # == 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 (def after_find). 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 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 (def after_find). In that case, all of the # callback types will be called. # # == before_validation* 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 ActiveRecord::RecordInvalid exception. - # Nothing will be appended to the errors object. + # 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 + # ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object. # # == Canceling 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 - # defined as methods on the model, which are called last. + # 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 defined as + # methods on the model, which are called last. # # == Transactions # @@ -217,7 +220,8 @@ module ActiveRecord # # == Debugging callbacks # - # To list the methods and procs registered with a particular callback, append _callback_chain to the callback name that you wish to list and send that to your class from the Rails console: + # To list the methods and procs registered with a particular callback, append _callback_chain to + # the callback name that you wish to list and send that to your class from the Rails console: # # >> Topic.after_save_callback_chain # => [#supplier_id in supplier_id int(11). # +default+ is the type-casted default value, such as +new+ in sales_stage varchar(20) default 'new'. - # +sql_type+ is used to extract the column's length, if necessary. For example +60+ in company_name varchar(60). + # +sql_type+ is used to extract the column's length, if necessary. For example +60+ in + # company_name varchar(60). # It will be mapped to one of the standard Rails SQL types in the type attribute. # +null+ determines if this column allows +NULL+ values. def initialize(name, default, sql_type = nil, null = true) @@ -359,7 +360,8 @@ def [](name) # # Available options are (none of these exists by default): # * :limit - - # Requests a maximum column length. This is number of characters for :string and :text columns and number of bytes for :binary and :integer columns. + # Requests a maximum column length. This is number of characters for :string and + # :text columns and number of bytes for :binary and :integer columns. # * :default - # The column's default value. Use nil for NULL. # * :null - @@ -462,8 +464,8 @@ def [](name) # TableDefinition#timestamps that'll add created_at and +updated_at+ as datetimes. # # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type - # column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be - # used when creating the _type column. So what can be written like this: + # column if the :polymorphic option is supplied. If :polymorphic is a hash of + # options, these will be used when creating the _type column. So what can be written like this: # # create_table :taggings do |t| # t.integer :tag_id, :tagger_id, :taggable_id diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index b403443d8e710..cc7c07dc354f4 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -278,7 +278,8 @@ def select_rows(sql, name = nil) rows end - # Executes a SQL query and returns a MySQL::Result object. Note that you have to free the Result object after you're done using it. + # Executes a SQL query and returns a MySQL::Result object. Note that you have to free + # the Result object after you're done using it. def execute(sql, name = nil) #:nodoc: if name == :skip_logging @connection.query(sql) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 37e94502a4f01..6fae899e8770a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -183,10 +183,14 @@ module ConnectionAdapters # * :username - Defaults to nothing. # * :password - Defaults to nothing. # * :database - The name of the database. No default, must be provided. - # * :schema_search_path - An optional schema search path for the connection given as a string of comma-separated schema names. This is backward-compatible with the :schema_order option. - # * :encoding - An optional client encoding that is used in a SET client_encoding TO call on the connection. - # * :min_messages - An optional client min messages that is used in a SET client_min_messages TO call on the connection. - # * :allow_concurrency - If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods. + # * :schema_search_path - An optional schema search path for the connection given + # as a string of comma-separated schema names. This is backward-compatible with the :schema_order option. + # * :encoding - An optional client encoding that is used in a SET client_encoding TO + # call on the connection. + # * :min_messages - An optional client min messages that is used in a + # SET client_min_messages TO call on the connection. + # * :allow_concurrency - If true, use async query methods so Ruby threads don't deadlock; + # otherwise, use blocking query methods. class PostgreSQLAdapter < AbstractAdapter ADAPTER_NAME = 'PostgreSQL'.freeze diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index e812a0371b473..82ad0a3b8eb08 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -29,8 +29,8 @@ def binary_to_string(value) end end - # The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby drivers (available both as gems and - # from http://rubyforge.org/projects/sqlite-ruby/). + # The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby + # drivers (available both as gems and from http://rubyforge.org/projects/sqlite-ruby/). # # Options: # diff --git a/activerecord/lib/active_record/dynamic_finder_match.rb b/activerecord/lib/active_record/dynamic_finder_match.rb index dfb8a3ba6033d..0dc965bd26f5a 100644 --- a/activerecord/lib/active_record/dynamic_finder_match.rb +++ b/activerecord/lib/active_record/dynamic_finder_match.rb @@ -2,8 +2,8 @@ module ActiveRecord # = Active Record Dynamic Finder Match # - # Provides dynamic attribute-based finders such as find_by_country - # if, for example, the Person has an attribute with that name. + # Refer to ActiveRecord::Base documentation for Dynamic attribute-based finders for detailed info + # class DynamicFinderMatch def self.match(method) df_match = self.new(method) diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 7aa725d095a34..e9ac5516eca97 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -30,7 +30,8 @@ class AssociationTypeMismatch < ActiveRecordError class SerializationTypeMismatch < ActiveRecordError end - # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). + # Raised when adapter not specified on connection (or configuration file config/database.yml + # misses adapter field). class AdapterNotSpecified < ActiveRecordError end @@ -38,7 +39,8 @@ class AdapterNotSpecified < ActiveRecordError class AdapterNotFound < ActiveRecordError end - # Raised when connection to the database could not been established (for example when connection= is given a nil object). + # Raised when connection to the database could not been established (for example when connection= + # is given a nil object). class ConnectionNotEstablished < ActiveRecordError end @@ -51,7 +53,8 @@ class RecordNotFound < ActiveRecordError class RecordNotSaved < ActiveRecordError end - # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old). + # Raised when SQL statement cannot be executed by the database (for example, it's often the case for + # MySQL when Ruby driver used is too old). class StatementInvalid < ActiveRecordError end @@ -78,7 +81,8 @@ class RecordNotUnique < WrappedDatabaseException class InvalidForeignKey < WrappedDatabaseException end - # Raised when number of bind variables in statement given to :condition key (for example, when using +find+ method) + # Raised when number of bind variables in statement given to :condition key (for example, + # when using +find+ method) # does not match number of expected variables. # # For example, in @@ -165,4 +169,4 @@ def initialize(errors) @errors = errors end end -end \ No newline at end of file +end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 657303fd141d1..e44102b5389d4 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -39,9 +39,10 @@ class FixtureClassNotFound < StandardError #:nodoc: # This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures # in a non-verbose, human-readable format. It ships with Ruby 1.8.1+. # -# Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed -# by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures/). The fixture file ends with the .yml file extension (Rails example: +# Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed +# in the directory appointed by ActiveSupport::TestCase.fixture_path=(path) (this is +# automatically configured for Rails, so you can just put your files in /test/fixtures/). +# The fixture file ends with the .yml file extension (Rails example: # /test/fixtures/web_sites.yml). The format of a YAML fixture file looks like this: # # rubyonrails: @@ -58,7 +59,8 @@ class FixtureClassNotFound < StandardError #:nodoc: # indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing # pleasure. # -# Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type. See http://yaml.org/type/omap.html +# Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type. +# See http://yaml.org/type/omap.html # for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table. # This is commonly needed for tree structures. Example: # @@ -79,7 +81,8 @@ class FixtureClassNotFound < StandardError #:nodoc: # (Rails example: /test/fixtures/web_sites.csv). # # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us -# humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised +# humans. The first line of the CSV file is a comma-separated list of field names. The rest of the +# file is then comprised # of the actual data (1 per line). Here's an example: # # id, name, url @@ -99,15 +102,16 @@ class FixtureClassNotFound < StandardError #:nodoc: # # == Single-file fixtures # -# This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats. -# Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory -# appointed by ActiveSupport::TestCase.fixture_path=(path) (this is automatically configured for Rails, so you can just -# put your files in /test/fixtures// -- +# This type of fixture was the original format for Active Record that has since been deprecated in +# favor of the YAML and CSV formats. +# Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) +# to the directory appointed by ActiveSupport::TestCase.fixture_path=(path) (this is automatically +# configured for Rails, so you can just put your files in /test/fixtures// -- # like /test/fixtures/web_sites/ for the WebSite model). # # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without -# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the -# above example might look like: +# extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. +# Here's what the above example might look like: # # web_sites/google # web_sites/yahoo.txt @@ -133,7 +137,8 @@ class FixtureClassNotFound < StandardError #:nodoc: # end # end # -# By default, the test_helper module will load all of your fixtures into your test database, so this test will succeed. +# By default, the test_helper module will load all of your fixtures into your test database, +# so this test will succeed. # The testing environment will automatically load the all fixtures into the database before each test. # To ensure consistent data, the environment deletes the fixtures before running the load. # @@ -182,13 +187,15 @@ class FixtureClassNotFound < StandardError #:nodoc: # This will create 1000 very simple YAML fixtures. # # Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>. -# This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable -# sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application -# is properly testable. Hence, dynamic values in fixtures are to be considered a code smell. +# This is however a feature to be used with some caution. The point of fixtures are that they're +# stable units of predictable sample data. If you feel that you need to inject dynamic values, then +# perhaps you should reexamine whether your application is properly testable. Hence, dynamic values +# in fixtures are to be considered a code smell. # # = Transactional fixtures # -# TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case. +# TestCases can use begin+rollback to isolate their changes to the database instead of having to +# delete+insert for every test case. # # class FooTest < ActiveSupport::TestCase # self.use_transactional_fixtures = true @@ -205,15 +212,18 @@ class FixtureClassNotFound < StandardError #:nodoc: # end # # If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures, -# then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes. +# then you may omit all fixtures declarations in your test cases since all the data's already there +# and every case rolls back its changes. # # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide -# access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+) +# access to fixture data for every table that has been loaded through fixtures (depending on the +# value of +use_instantiated_fixtures+) # # When *not* to use transactional fixtures: # -# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit, -# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify +# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until +# all parent transactions commit, particularly, the fixtures transaction which is begun in setup +# and rolled back in teardown. Thus, you won't be able to verify # the results of your transaction until Active Record supports nested transactions or savepoints (in progress). # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM. # Use InnoDB, MaxDB, or NDB instead. diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 417ff4b5ebf62..0e560418dc0ec 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -48,18 +48,21 @@ def scopes # The above calls to scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, # in effect, represents the query Shirt.where(:color => 'red'). # - # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object - # constructed by a has_many declaration. For instance, you can invoke Shirt.red.first, Shirt.red.count, - # Shirt.red.where(:size => 'small'). Also, just as with the association objects, named \scopes act like an Array, - # implementing Enumerable; Shirt.red.each(&block), Shirt.red.first, and Shirt.red.inject(memo, &block) + # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it + # resembles the association object constructed by a has_many declaration. For instance, + # you can invoke Shirt.red.first, Shirt.red.count, Shirt.red.where(:size => 'small'). + # Also, just as with the association objects, named \scopes act like an Array, implementing Enumerable; + # Shirt.red.each(&block), Shirt.red.first, and Shirt.red.inject(memo, &block) # all behave as if Shirt.red really was an Array. # - # These named \scopes are composable. For instance, Shirt.red.dry_clean_only will produce all shirts that are both red and dry clean only. - # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments - # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). + # These named \scopes are composable. For instance, Shirt.red.dry_clean_only will produce + # all shirts that are both red and dry clean only. + # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count + # returns the number of garments for which these criteria obtain. Similarly with + # Shirt.red.dry_clean_only.average(:thread_count). # - # All \scopes are available as class methods on the ActiveRecord::Base descendant upon which the \scopes were defined. But they are also available to - # has_many associations. If, + # All \scopes are available as class methods on the ActiveRecord::Base descendant upon which + # the \scopes were defined. But they are also available to has_many associations. If, # # class Person < ActiveRecord::Base # has_many :shirts diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index ce002f5e1aa2d..78bac55bf2f0d 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -67,8 +67,8 @@ module ActiveRecord # # == Configuration # - # In order to activate an observer, list it in the config.active_record.observers configuration setting in your - # config/application.rb file. + # In order to activate an observer, list it in the config.active_record.observers configuration + # setting in your config/application.rb file. # # config.active_record.observers = :comment_observer, :signup_observer # diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index cbc2220e96878..8f44f03d56e7d 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -91,8 +91,8 @@ def destroy # like render :partial => @client.becomes(Company) to render that # instance using the companies/company partial instead of clients/client. # - # Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either - # instance will affect the other. + # Note: The new instance will share a link to the same attributes as the original class. + # So any change to the attributes in either instance will affect the other. def becomes(klass) became = klass.new became.instance_variable_set("@attributes", @attributes) diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 7962f52738bc5..deacced6277d2 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -67,7 +67,8 @@ def to_a preload += @includes_values unless eager_loading? preload.each {|associations| @klass.send(:preload_associations, @records, associations) } - # @readonly_value is true only if set explicitly. @implicit_readonly is true if there are JOINS and no explicit SELECT. + # @readonly_value is true only if set explicitly. @implicit_readonly is true if there + # are JOINS and no explicit SELECT. readonly = @readonly_value.nil? ? @implicit_readonly : @readonly_value @records.each { |record| record.readonly! } if readonly @@ -130,7 +131,8 @@ def scoping # ==== Parameters # # * +updates+ - A string, array, or hash representing the SET part of an SQL statement. - # * +conditions+ - A string, array, or hash representing the WHERE part of an SQL statement. See conditions in the intro. + # * +conditions+ - A string, array, or hash representing the WHERE part of an SQL statement. + # See conditions in the intro. # * +options+ - Additional options are :limit and :order, see the examples for usage. # # ==== Examples @@ -144,7 +146,7 @@ def scoping # # Update all avatars migrated more than a week ago # Avatar.update_all ['migrated_at = ?', Time.now.utc], ['migrated_at > ?', 1.week.ago] # - # # Update all books that match our conditions, but limit it to 5 ordered by date + # # Update all books that match conditions, but limit it to 5 ordered by date # Book.update_all "author = 'David'", "title LIKE '%Rails%'", :order => 'created_at', :limit => 5 def update_all(updates, conditions = nil, options = {}) if conditions || options.present? @@ -165,14 +167,14 @@ def update_all(updates, conditions = nil, options = {}) # ==== Parameters # # * +id+ - This should be the id or an array of ids to be updated. - # * +attributes+ - This should be a hash of attributes to be set on the object, or an array of hashes. + # * +attributes+ - This should be a hash of attributes or an array of hashes. # # ==== Examples # - # # Updating one record: + # # Updates one record # Person.update(15, :user_name => 'Samuel', :group => 'expert') # - # # Updating multiple records: + # # Updates multiple records # people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } } # Person.update(people.keys, people.values) def update(id, attributes) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 44baeb6c843f8..f8412bc604d88 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -5,26 +5,33 @@ module Calculations # Count operates using three different approaches. # # * Count all: By not passing any parameters to count, it will return a count of all the rows for the model. - # * Count using column: By passing a column name to count, it will return a count of all the rows for the model with supplied column present + # * Count using column: By passing a column name to count, it will return a count of all the + # rows for the model with supplied column present # * Count using options will find the row count matched by the options used. # # The third approach, count using options, accepts an option hash as the only parameter. The options are: # - # * :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro to ActiveRecord::Base. + # * :conditions: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. + # See conditions in the intro to ActiveRecord::Base. # * :joins: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed) - # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s). - # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. + # or named associations in the same form used for the :include option, which will + # perform an INNER JOIN on the associated table(s). + # If the value is a string, then the records will be returned read-only since they will have + # attributes that do not correspond to the table's columns. # Pass :readonly => false to override. - # * :include: Named associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer - # to already defined associations. When using named associations, count returns the number of DISTINCT items for the model you're counting. + # * :include: Named associations that should be loaded alongside using LEFT OUTER JOINs. + # The symbols named refer to already defined associations. When using named associations, count + # returns the number of DISTINCT items for the model you're counting. # See eager loading under Associations. # * :order: An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations). # * :group: An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :select: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not + # * :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. - # * :distinct: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ... - # * :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name - # of a database view). + # * :distinct: Set this to true to make this a distinct calculation, such as + # SELECT COUNT(DISTINCT posts.id) ... + # * :from - By default, this is the table name of the class, but can be changed to an + # alternate table name (or even the name of a database view). # # Examples for counting all: # Person.count # returns the total count of all people @@ -34,12 +41,19 @@ module Calculations # # Examples for count with options: # Person.count(:conditions => "age > 26") - # Person.count(:conditions => "age > 26 AND job.salary > 60000", :include => :job) # because of the named association, it finds the DISTINCT count using LEFT OUTER JOIN. - # Person.count(:conditions => "age > 26 AND job.salary > 60000", :joins => "LEFT JOIN jobs on jobs.person_id = person.id") # finds the number of rows matching the conditions and joins. + # + # # because of the named association, it finds the DISTINCT count using LEFT OUTER JOIN. + # Person.count(:conditions => "age > 26 AND job.salary > 60000", :include => :job) + # + # # finds the number of rows matching the conditions and joins. + # Person.count(:conditions => "age > 26 AND job.salary > 60000", + # :joins => "LEFT JOIN jobs on jobs.person_id = person.id") + # # Person.count('id', :conditions => "age > 26") # Performs a COUNT(id) # Person.count(:all, :conditions => "age > 26") # Performs a COUNT(*) (:all is an alias for '*') # - # Note: Person.count(:all) will not work because it will use :all as the condition. Use Person.count instead. + # Note: Person.count(:all) will not work because it will use :all as the condition. + # Use Person.count instead. def count(column_name = nil, options = {}) column_name, options = nil, column_name if column_name.is_a?(Hash) calculate(:count, column_name, options) @@ -80,13 +94,15 @@ def sum(column_name, options = {}) calculate(:sum, column_name, options) end - # This calculates aggregate values in the given column. Methods for count, sum, average, minimum, and maximum have been added as shortcuts. - # Options such as :conditions, :order, :group, :having, and :joins can be passed to customize the query. + # This calculates aggregate values in the given column. Methods for count, sum, average, + # minimum, and maximum have been added as shortcuts. Options such as :conditions, + # :order, :group, :having, and :joins can be passed to customize the query. # # There are two basic forms of output: - # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float for AVG, and the given column's type for everything else. - # * Grouped values: This returns an ordered hash of the values and groups them by the :group option. It takes either a column name, or the name - # of a belongs_to association. + # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float + # for AVG, and the given column's type for everything else. + # * Grouped values: This returns an ordered hash of the values and groups them by the + # :group option. It takes either a column name, or the name of a belongs_to association. # # values = Person.maximum(:age, :group => 'last_name') # puts values["Drake"] @@ -102,21 +118,30 @@ def sum(column_name, options = {}) # end # # Options: - # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro to ActiveRecord::Base. - # * :include: Eager loading, see Associations for details. Since calculations don't load anything, the purpose of this is to access fields on joined tables in your conditions, order, or group clauses. - # * :joins - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed). - # The records will be returned read-only since they will have attributes that do not correspond to the table's columns. + # * :conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. + # See conditions in the intro to ActiveRecord::Base. + # * :include: Eager loading, see Associations for details. Since calculations don't load anything, + # the purpose of this is to access fields on joined tables in your conditions, order, or group clauses. + # * :joins - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". + # (Rarely needed). + # The records will be returned read-only since they will have attributes that do not correspond to the + # table's columns. # * :order - An SQL fragment like "created_at DESC, name" (really only used with GROUP BY calculations). # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :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. - # * :distinct - Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ... + # * :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. + # * :distinct - Set this to true to make this a distinct calculation, such as + # SELECT COUNT(DISTINCT posts.id) ... # # Examples: # Person.calculate(:count, :all) # The same as Person.count # Person.average(:age) # SELECT AVG(age) FROM people... - # Person.minimum(:age, :conditions => ['last_name != ?', 'Drake']) # Selects the minimum age for everyone with a last name other than 'Drake' - # Person.minimum(:age, :having => 'min(age) > 17', :group => :last_name) # Selects the minimum age for any family without any minors + # Person.minimum(:age, :conditions => ['last_name != ?', 'Drake']) # Selects the minimum age for + # # everyone with a last name other than 'Drake' + # + # # Selects the minimum age for any family without any minors + # Person.minimum(:age, :having => 'min(age) > 17', :group => :last_name) + # # Person.sum("2 * age") def calculate(operation, column_name, options = {}) if options.except(:distinct).present? diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 3bf4c5bdd18d3..a192e044eaef5 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -21,23 +21,28 @@ module FinderMethods # # ==== Parameters # - # * :conditions - An SQL fragment like "administrator = 1", [ "user_name = ?", username ], or ["user_name = :user_name", { :user_name => user_name }]. See conditions in the intro. + # * :conditions - An SQL fragment like "administrator = 1", [ "user_name = ?", username ], + # or ["user_name = :user_name", { :user_name => user_name }]. See conditions in the intro. # * :order - An SQL fragment like "created_at DESC, name". # * :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause. - # * :having - Combined with +:group+ this can be used to filter the records that a GROUP BY returns. Uses the HAVING SQL-clause. + # * :having - Combined with +:group+ this can be used to filter the records that a + # GROUP BY returns. Uses the HAVING 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 rows 0 through 4. + # * :offset - An integer determining the offset from where the rows should be fetched. So at 5, + # it would skip rows 0 through 4. # * :joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed), - # named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s), + # named associations in the same form used for the :include option, which will perform an + # INNER JOIN on the associated table(s), # or an array containing a mixture of both strings and named associations. - # If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. + # If the value is a string, then the records will be returned read-only since they will + # have attributes that do not correspond to the table's columns. # Pass :readonly => false to override. # * :include - Names associations that should be loaded alongside. The symbols named refer # to already defined associations. See eager loading under Associations. - # * :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. Takes a string with the SELECT SQL fragment (e.g. "id, name"). - # * :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name - # of a database view). + # * :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. Takes a string with the SELECT SQL fragment (e.g. "id, name"). + # * :from - By default, this is the table name of the class, but can be changed + # to an alternate table name (or even the name of a database view). # * :readonly - Mark the returned records read-only so they cannot be saved or updated. # * :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb index 32b3f03f13158..5531d12a41497 100644 --- a/activerecord/lib/active_record/timestamp.rb +++ b/activerecord/lib/active_record/timestamp.rb @@ -21,7 +21,8 @@ module ActiveRecord # # This feature can easily be turned off by assigning value false . # - # If your attributes are time zone aware and you desire to skip time zone conversion for certain attributes then you can do following: + # If your attributes are time zone aware and you desire to skip time zone conversion for certain + # attributes then you can do following: # # Topic.skip_time_zone_conversion_for_attributes = [:written_on] module Timestamp diff --git a/activerecord/lib/active_record/validations/associated.rb b/activerecord/lib/active_record/validations/associated.rb index 0b0f5682aa092..15b587de450e5 100644 --- a/activerecord/lib/active_record/validations/associated.rb +++ b/activerecord/lib/active_record/validations/associated.rb @@ -27,8 +27,9 @@ module ClassMethods # # this would specify a circular dependency and cause infinite recursion. # - # NOTE: This validation will not fail if the association hasn't been assigned. If you want to ensure that the association - # is both present and guaranteed to be valid, you also need to use +validates_presence_of+. + # NOTE: This validation will not fail if the association hasn't been assigned. If you want to + # ensure that the association is both present and guaranteed to be valid, you also need to + # use +validates_presence_of+. # # Configuration options: # * :message - A custom error message (default is: "is invalid") @@ -44,4 +45,4 @@ def validates_associated(*attr_names) end end end -end \ No newline at end of file +end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 1c9ecc7b1b2aa..bf863c70632b1 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -78,22 +78,25 @@ def mount_sql_and_params(klass, table_name, attribute, value) #:nodoc: end module ClassMethods - # Validates whether the value of the specified attributes are unique across the system. Useful for making sure that only one user + # Validates whether the value of the specified attributes are unique across the system. + # Useful for making sure that only one user # can be named "davidhh". # # class Person < ActiveRecord::Base # validates_uniqueness_of :user_name, :scope => :account_id # end # - # It can also validate whether the value of the specified attributes are unique based on multiple scope parameters. For example, - # making sure that a teacher can only be on the schedule once per semester for a particular class. + # It can also validate whether the value of the specified attributes are unique based on multiple + # scope parameters. For example, making sure that a teacher can only be on the schedule once + # per semester for a particular class. # # class TeacherSchedule < ActiveRecord::Base # validates_uniqueness_of :teacher_id, :scope => [:semester_id, :class_id] # end # - # When the record is created, a check is performed to make sure that no record exists in the database with the given value for the specified - # attribute (that maps to a column). When the record is updated, the same check is made but disregarding the record itself. + # When the record is created, a check is performed to make sure that no record exists in the database + # with the given value for the specified attribute (that maps to a column). When the record is updated, + # the same check is made but disregarding the record itself. # # Configuration options: # * :message - Specifies a custom error message (default is: "has already been taken"). @@ -102,11 +105,12 @@ module ClassMethods # * :allow_nil - If set to true, skips this validation if the attribute is +nil+ (default is +false+). # * :allow_blank - If set to true, skips this validation if the attribute is blank (default is +false+). # * :if - Specifies a method, proc or string to call to determine if the validation should - # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The - # method, proc or string should return or evaluate to a true or false value. + # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). + # The method, proc or string should return or evaluate to a true or false value. # * :unless - Specifies a method, proc or string to call to determine if the validation should - # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The - # method, proc or string should return or evaluate to a true or false value. + # not occur (e.g. :unless => :skip_validation, or + # :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should + # return or evaluate to a true or false value. # # === Concurrency and integrity #