diff options
Diffstat (limited to 'activerecord/lib/active_record')
21 files changed, 548 insertions, 239 deletions
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 7e4f7a5d4a..3e7c787dee 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -59,14 +59,14 @@ module ActiveRecord def set_association_collection_records(id_to_record_map, reflection_name, associated_records, key) associated_records.each do |associated_record| - mapped_records = id_to_record_map[associated_record[key].to_i] + mapped_records = id_to_record_map[associated_record[key].to_s] add_preloaded_records_to_collection(mapped_records, reflection_name, associated_record) end end def set_association_single_records(id_to_record_map, reflection_name, associated_records, key) associated_records.each do |associated_record| - mapped_records = id_to_record_map[associated_record[key].to_i] + mapped_records = id_to_record_map[associated_record[key].to_s] mapped_records.each do |mapped_record| mapped_record.send("set_#{reflection_name}_target", associated_record) end @@ -78,16 +78,15 @@ module ActiveRecord ids = [] records.each do |record| ids << record.id - mapped_records = (id_to_record_map[record.id] ||= []) + mapped_records = (id_to_record_map[record.id.to_s] ||= []) mapped_records << record end ids.uniq! return id_to_record_map, ids end - # FIXME: quoting def preload_has_and_belongs_to_many_association(records, reflection, preload_options={}) - table_name = reflection.klass.table_name + table_name = reflection.klass.quoted_table_name id_to_record_map, ids = construct_id_map(records) records.each {|record| record.send(reflection.name).loaded} options = reflection.options @@ -97,7 +96,7 @@ module ActiveRecord associated_records = reflection.klass.find(:all, :conditions => [conditions, ids], :include => options[:include], - :joins => "INNER JOIN #{options[:join_table]} as t0 ON #{reflection.klass.table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}", + :joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}", :select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as _parent_record_id", :order => options[:order]) @@ -116,7 +115,7 @@ module ActiveRecord source = reflection.source_reflection.name through_records.first.class.preload_associations(through_records, source) through_records.each do |through_record| - add_preloaded_record_to_collection(id_to_record_map[through_record[through_primary_key].to_i], + add_preloaded_record_to_collection(id_to_record_map[through_record[through_primary_key].to_s], reflection.name, through_record.send(source)) end end @@ -141,7 +140,7 @@ module ActiveRecord source = reflection.source_reflection.name through_records.first.class.preload_associations(through_records, source) through_records.each do |through_record| - add_preloaded_records_to_collection(id_to_record_map[through_record[through_primary_key].to_i], + add_preloaded_records_to_collection(id_to_record_map[through_record[through_primary_key].to_s], reflection.name, through_record.send(source)) end end @@ -157,7 +156,7 @@ module ActiveRecord if reflection.options[:source_type] interface = reflection.source_reflection.options[:foreign_type] - preload_options = {:conditions => ["#{interface} = ?", reflection.options[:source_type]]} + preload_options = {:conditions => ["#{connection.quote_column_name interface} = ?", reflection.options[:source_type]]} records.compact! records.first.class.preload_associations(records, through_association, preload_options) @@ -196,18 +195,22 @@ module ActiveRecord records.each do |record| if klass = record.send(polymorph_type) klass_id = record.send(primary_key_name) - - id_map = klasses_and_ids[klass] ||= {} - id_list_for_klass_id = (id_map[klass_id] ||= []) - id_list_for_klass_id << record + if klass_id + id_map = klasses_and_ids[klass] ||= {} + id_list_for_klass_id = (id_map[klass_id.to_s] ||= []) + id_list_for_klass_id << record + end end end klasses_and_ids = klasses_and_ids.to_a else id_map = {} records.each do |record| - mapped_records = (id_map[record.send(primary_key_name)] ||= []) - mapped_records << record + key = record.send(primary_key_name) + if key + mapped_records = (id_map[key.to_s] ||= []) + mapped_records << record + end end klasses_and_ids = [[reflection.klass.name, id_map]] end @@ -216,7 +219,7 @@ module ActiveRecord klass_name, id_map = *klass_and_id klass = klass_name.constantize - table_name = klass.table_name + table_name = klass.quoted_table_name primary_key = klass.primary_key conditions = "#{table_name}.#{primary_key} IN (?)" conditions << append_conditions(options, preload_options) @@ -229,16 +232,15 @@ module ActiveRecord end end - # FIXME: quoting def find_associated_records(ids, reflection, preload_options) options = reflection.options - table_name = reflection.klass.table_name + table_name = reflection.klass.quoted_table_name if interface = reflection.options[:as] - conditions = "#{reflection.klass.table_name}.#{interface}_id IN (?) and #{reflection.klass.table_name}.#{interface}_type = '#{self.base_class.name.demodulize}'" + conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} IN (?) and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.name.demodulize}'" else foreign_key = reflection.primary_key_name - conditions = "#{reflection.klass.table_name}.#{foreign_key} IN (?)" + conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} IN (?)" end conditions << append_conditions(options, preload_options) diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb index df21124e92..c415ad2df3 100644 --- a/activerecord/lib/active_record/associations/association_proxy.rb +++ b/activerecord/lib/active_record/associations/association_proxy.rb @@ -179,6 +179,16 @@ module ActiveRecord end end + # Loads the target if needed and returns it. + # + # This method is abstract in the sense that it relies on +find_target+, + # which is expected to be provided by descendants. + # + # If the target is already loaded it is just returned. Thus, you can call + # +load_target+ unconditionally to get the target. + # + # ActiveRecord::RecordNotFound is rescued within the method, and it is + # not reraised. The proxy is reset and +nil+ is the return value. def load_target return nil unless defined?(@loaded) 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 ebea313c18..f683669615 100644 --- a/activerecord/lib/active_record/associations/has_many_through_association.rb +++ b/activerecord/lib/active_record/associations/has_many_through_association.rb @@ -10,14 +10,14 @@ module ActiveRecord def create!(attrs = nil) @reflection.klass.transaction do - self << (object = @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create! }) + self << (object = attrs ? @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create! } : @reflection.klass.create!) object end end def create(attrs = nil) @reflection.klass.transaction do - self << (object = @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create }) + self << (object = attrs ? @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create } : @reflection.klass.create) object end end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 8bef5ed2ae..ffefc3cef3 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -11,22 +11,18 @@ module ActiveRecord #:nodoc: class SubclassNotFound < ActiveRecordError #:nodoc: end - # Raised when object assigned to association is of incorrect type. + # Raised when an object assigned to an association has an incorrect type. # - # Example: - # - # class Ticket < ActiveRecord::Base - # has_many :patches - # end - # - # class Patch < ActiveRecord::Base - # belongs_to :ticket - # end + # class Ticket < ActiveRecord::Base + # has_many :patches + # end # - # and somewhere in the code: + # class Patch < ActiveRecord::Base + # belongs_to :ticket + # end # - # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.") - # @ticket.save + # # Comments are not patches, this assignment raises AssociationTypeMismatch. + # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.") class AssociationTypeMismatch < ActiveRecordError end @@ -59,14 +55,14 @@ module ActiveRecord #:nodoc: class StatementInvalid < ActiveRecordError 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 <tt>:condition</tt> key (for example, when using +find+ method) # does not match number of expected variables. # - # Example: + # For example, in # - # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362] + # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362] # - # in example above two placeholders are given but only one variable to fill them. + # two placeholders are given but only one variable to fill them. class PreparedStatementInvalid < ActiveRecordError end @@ -97,8 +93,8 @@ module ActiveRecord #:nodoc: end # Raised when you've tried to access a column which wasn't - # loaded by your finder. Typically this is because :select - # has been specified + # loaded by your finder. Typically this is because <tt>:select</tt> + # has been specified. class MissingAttributeError < NoMethodError end @@ -206,7 +202,7 @@ module ActiveRecord #:nodoc: # # Uses an integer of seconds to hold the length of the song # # def length=(minutes) - # write_attribute(:length, minutes * 60) + # write_attribute(:length, minutes.to_i * 60) # end # # def length @@ -256,7 +252,7 @@ module ActiveRecord #:nodoc: # # It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount # is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is - # actually Person.find_by_user_name(user_name, options). So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>. + # actually <tt>Person.find_by_user_name(user_name, options)</tt>. So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>. # # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with # <tt>find_or_create_by_</tt> 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: @@ -423,7 +419,9 @@ module ActiveRecord #:nodoc: @@default_timezone = :local # Determines whether to use a connection for each thread, or a single shared connection for all threads. - # Defaults to false. Set to true if you're writing a threaded application. + # Defaults to false. If you're writing a threaded application, set to true + # and periodically call verify_active_connections! to clear out connections + # assigned to stale threads. cattr_accessor :allow_concurrency, :instance_writer => false @@allow_concurrency = false @@ -455,9 +453,9 @@ module ActiveRecord #:nodoc: # * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned. # * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4. # * <tt>:joins</tt>: 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). + # or named associations in the same form used for the <tt>:include</tt> 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. + # Pass <tt>:readonly => false</tt> to override. # * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer # to already defined associations. See eager loading under Associations. # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not @@ -466,7 +464,7 @@ module ActiveRecord #:nodoc: # of a database view). # * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated. # * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". - # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE". + # <tt>:lock => true</tt> gives connection's default exclusive lock, usually "FOR UPDATE". # # Examples for find by id: # Person.find(1) # returns the object for ID = 1 @@ -476,7 +474,7 @@ module ActiveRecord #:nodoc: # Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC") # # Note that returned records may not be in the same order as the ids you - # provide since database rows are unordered. Give an explicit :order + # provide since database rows are unordered. Give an explicit <tt>:order</tt> # to ensure the results are sorted. # # Examples for find first: @@ -532,6 +530,12 @@ module ActiveRecord #:nodoc: find(:last, *args) end + # This is an alias for find(:all). You can pass in all the same arguments to this method as you can + # to find(:all) + def all(*args) + find(:all, *args) + end + # # Executes a custom sql query against your database and returns all the results. The results will # be returned as an array with columns requested encapsulated as attributes of the model you call @@ -595,13 +599,25 @@ module ActiveRecord #:nodoc: # ==== Examples # # Create a single new object # User.create(:first_name => 'Jamie') + # # # Create an Array of new objects # User.create([{:first_name => 'Jamie'}, {:first_name => 'Jeremy'}]) - def create(attributes = nil) + # + # # Create a single object and pass it into a block to set other attributes. + # User.create(:first_name => 'Jamie') do |u| + # u.is_admin = false + # end + # + # # Creating an Array of new objects using a block, where the block is executed for each object: + # User.create([{:first_name => 'Jamie'}, {:first_name => 'Jeremy'}]) do |u| + # u.is_admin = false + # end + def create(attributes = nil, &block) if attributes.is_a?(Array) - attributes.collect { |attr| create(attr) } + attributes.collect { |attr| create(attr, &block) } else object = new(attributes) + yield(object) if block_given? object.save object end @@ -691,7 +707,7 @@ module ActiveRecord #:nodoc: # +updates+ A String of column and value pairs that will be set on any records that match conditions # +conditions+ An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. # See conditions in the intro for more info. - # +options+ Additional options are :limit and/or :order, see the examples for usage. + # +options+ Additional options are <tt>:limit</tt> and/or <tt>:order</tt>, see the examples for usage. # # ==== Examples # @@ -1272,7 +1288,7 @@ module ActiveRecord #:nodoc: private def find_initial(options) - options.update(:limit => 1) unless options[:include] + options.update(:limit => 1) find_every(options).first end @@ -1501,7 +1517,7 @@ module ActiveRecord #:nodoc: end end - # The optional scope argument is for the current :find scope. + # The optional scope argument is for the current <tt>:find</tt> scope. def add_limit!(sql, options, scope = :auto) scope = scope(:find) if :auto == scope @@ -1513,15 +1529,15 @@ module ActiveRecord #:nodoc: connection.add_limit_offset!(sql, options) end - # The optional scope argument is for the current :find scope. - # The :lock option has precedence over a scoped :lock. + # The optional scope argument is for the current <tt>:find</tt> scope. + # The <tt>:lock</tt> option has precedence over a scoped <tt>:lock</tt>. def add_lock!(sql, options, scope = :auto) scope = scope(:find) if :auto == scope options = options.reverse_merge(:lock => scope[:lock]) if scope connection.add_lock!(sql, options) end - # The optional scope argument is for the current :find scope. + # The optional scope argument is for the current <tt>:find</tt> scope. def add_joins!(sql, options, scope = :auto) scope = scope(:find) if :auto == scope [(scope && scope[:joins]), options[:joins]].each do |join| @@ -1536,7 +1552,7 @@ module ActiveRecord #:nodoc: end # Adds a sanitized version of +conditions+ to the +sql+ string. Note that the passed-in +sql+ string is changed. - # The optional scope argument is for the current :find scope. + # The optional scope argument is for the current <tt>:find</tt> scope. def add_conditions!(sql, conditions, scope = :auto) scope = scope(:find) if :auto == scope conditions = [conditions] @@ -1733,8 +1749,8 @@ module ActiveRecord #:nodoc: protected # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash. - # method_name may be :find or :create. :find parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>, - # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. :create parameters are an attributes hash. + # method_name may be <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>, + # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. <tt>:create</tt> parameters are an attributes hash. # # class Article < ActiveRecord::Base # def self.create_with_scope @@ -1747,7 +1763,7 @@ module ActiveRecord #:nodoc: # end # # In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of - # :conditions and :include options in :find, which are merged. + # <tt>:conditions</tt> and <tt>:include</tt> options in <tt>:find</tt>, which are merged. # # class Article < ActiveRecord::Base # def self.find_with_scope @@ -2197,9 +2213,9 @@ module ActiveRecord #:nodoc: record end - # Returns an instance of the specified klass with the attributes of the current record. This is mostly useful in relation to + # Returns an instance of the specified +klass+ with the attributes of the current record. This is mostly useful in relation to # single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record - # identification in Action Pack to allow, say, Client < Company to do something like render :partial => @client.becomes(Company) + # identification in Action Pack to allow, say, <tt>Client < Company</tt> to do something like render <tt>:partial => @client.becomes(Company)</tt> # 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 diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb index b5bf82ee11..3c5caefe3b 100644 --- a/activerecord/lib/active_record/calculations.rb +++ b/activerecord/lib/active_record/calculations.rb @@ -9,16 +9,16 @@ module ActiveRecord # 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: # # * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro. # * <tt>:joins</tt>: 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). + # or named associations in the same form used for the <tt>:include</tt> 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. + # Pass <tt>:readonly => false</tt> to override. # * <tt>:include</tt>: 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. @@ -41,7 +41,7 @@ module ActiveRecord # 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: <tt>Person.count(:all)</tt> will not work because it will use <tt>:all</tt> as the condition. Use Person.count instead. def count(*args) calculate(:count, *construct_count_options_from_args(*args)) end @@ -75,11 +75,11 @@ module ActiveRecord 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. + # Options such as <tt>:conditions</tt>, <tt>:order</tt>, <tt>:group</tt>, <tt>:having</tt>, and <tt>:joins</tt> 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 + # * Grouped values: This returns an ordered hash of the values and groups them by the <tt>:group</tt> option. It takes either a column name, or the name # of a belongs_to association. # # values = Person.maximum(:age, :group => 'last_name') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index d950181566..34627dfaf9 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -175,7 +175,7 @@ module ActiveRecord end # Establishes the connection to the database. Accepts a hash as input where - # the :adapter key must be specified with the name of a database adapter (in lower-case) + # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case) # example for regular databases (MySQL, Postgresql, etc): # # ActiveRecord::Base.establish_connection( @@ -194,6 +194,7 @@ module ActiveRecord # ) # # Also accepts keys as strings (for parsing from yaml for example): + # # ActiveRecord::Base.establish_connection( # "adapter" => "sqlite", # "database" => "path/to/dbfile" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index d30f9b4d32..d73ffc3da6 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -398,8 +398,8 @@ module ActiveRecord # 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 <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of options, these will be + # used when creating the <tt>_type</tt> column. So what can be written like this: # # create_table :taggings do |t| # t.integer :tag_id, :tagger_id, :taggable_id @@ -469,5 +469,195 @@ module ActiveRecord @base.native_database_types end end + + # Represents a SQL table in an abstract way for updating a table. + # Also see TableDefinition and SchemaStatements#create_table + # + # Available transformations are: + # + # change_table :table do |t| + # t.column + # t.index + # t.timestamps + # t.change + # t.change_default + # t.rename + # t.references + # t.belongs_to + # t.string + # t.text + # t.integer + # t.float + # t.decimal + # t.datetime + # t.timestamp + # t.time + # t.date + # t.binary + # t.boolean + # t.remove + # t.remove_references + # t.remove_belongs_to + # t.remove_index + # t.remove_timestamps + # end + # + class Table + def initialize(table_name, base) + @table_name = table_name + @base = base + end + + # Adds a new column to the named table. + # See TableDefinition#column for details of the options you can use. + # ===== Examples + # ====== Creating a simple columns + # t.column(:name, :string) + def column(column_name, type, options = {}) + @base.add_column(@table_name, column_name, type, options) + end + + # Adds a new index to the table. +column_name+ can be a single Symbol, or + # an Array of Symbols. See SchemaStatements#add_index + # + # ===== Examples + # ====== Creating a simple index + # t.index(:name) + # ====== Creating a unique index + # t.index([:branch_id, :party_id], :unique => true) + # ====== Creating a named index + # t.index([:branch_id, :party_id], :unique => true, :name => 'by_branch_party') + def index(column_name, options = {}) + @base.add_index(@table_name, column_name, options) + end + + # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#timestamps + # ===== Examples + # t.timestamps + def timestamps + @base.add_timestamps(@table_name) + end + + # Changes the column's definition according to the new options. + # See TableDefinition#column for details of the options you can use. + # ===== Examples + # t.change(:name, :string, :limit => 80) + # t.change(:description, :text) + def change(column_name, type, options = {}) + @base.change_column(@table_name, column_name, type, options) + end + + # Sets a new default value for a column. See + # ===== Examples + # t.change_default(:qualification, 'new') + # t.change_default(:authorized, 1) + def change_default(column_name, default) + @base.change_column_default(@table_name, column_name, default) + end + + # Removes the column(s) from the table definition. + # ===== Examples + # t.remove(:qualification) + # t.remove(:qualification, :experience) + # t.removes(:qualification, :experience) + def remove(*column_names) + @base.remove_column(@table_name, column_names) + end + + # Remove the given index from the table. + # + # Remove the suppliers_name_index in the suppliers table. + # t.remove_index :name + # Remove the index named accounts_branch_id_index in the accounts table. + # t.remove_index :column => :branch_id + # Remove the index named accounts_branch_id_party_id_index in the accounts table. + # t.remove_index :column => [:branch_id, :party_id] + # Remove the index named by_branch_party in the accounts table. + # t.remove_index :name => :by_branch_party + def remove_index(options = {}) + @base.remove_index(@table_name, options) + end + + # Removes the timestamp columns (created_at and updated_at) from the table. + # ===== Examples + # t.remove_timestamps + def remove_timestamps + @base.remove_timestamps(@table_name) + end + + # Renames a column. + # ===== Example + # t.rename(:description, :name) + def rename(column_name, new_column_name) + @base.rename_column(@table_name, column_name, new_column_name) + end + + # Adds a reference. Optionally adds a +type+ column. <tt>reference</tt>, + # <tt>references</tt> and <tt>belongs_to</tt> are all acceptable + # ===== Example + # t.references(:goat) + # t.references(:goat, :polymorphic => true) + # t.references(:goat) + # t.belongs_to(:goat) + def references(*args) + options = args.extract_options! + polymorphic = options.delete(:polymorphic) + args.each do |col| + @base.add_column(@table_name, "#{col}_id", :integer, options) + @base.add_column(@table_name, "#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil? + end + end + alias :belongs_to :references + + # Adds a reference. Optionally removes a +type+ column. <tt>remove_reference</tt>, + # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are all acceptable + # ===== Example + # t.remove_reference(:goat) + # t.remove_reference(:goat, :polymorphic => true) + # t.remove_references(:goat) + # t.remove_belongs_to(:goat) + def remove_references(*args) + options = args.extract_options! + polymorphic = options.delete(:polymorphic) + args.each do |col| + @base.remove_column(@table_name, "#{col}_id") + @base.remove_column(@table_name, "#{col}_type") unless polymorphic.nil? + end + end + alias :remove_belongs_to :remove_references + + # Adds a column or columns of a specified type + # ===== Example + # t.string(:goat) + # t.string(:goat, :sheep) + %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type| + class_eval <<-EOV + def #{column_type}(*args) + options = args.extract_options! + column_names = args + + column_names.each do |name| + column = ColumnDefinition.new(@base, name, '#{column_type}') + if options[:limit] + column.limit = options[:limit] + elsif native['#{column_type}'.to_sym].is_a?(Hash) + column.limit = native['#{column_type}'.to_sym][:limit] + end + column.precision = options[:precision] + column.scale = options[:scale] + column.default = options[:default] + column.null = options[:null] + @base.add_column(@table_name, name, column.sql_type, options) + end + end + EOV + end + + private + def native + @base.native_database_types + end + end + end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index c986f0c6f1..6aae556d67 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -45,7 +45,7 @@ module ActiveRecord # The +options+ hash can include the following keys: # [<tt>:id</tt>] # Whether to automatically add a primary key column. Defaults to true. - # Join tables for has_and_belongs_to_many should set :id => false. + # Join tables for +has_and_belongs_to_many+ should set <tt>:id => false</tt>. # [<tt>:primary_key</tt>] # The name of the primary key, if one is to be added automatically. # Defaults to +id+. @@ -104,6 +104,67 @@ module ActiveRecord execute create_sql end + # A block for changing columns in +table+. + # + # === Example + # # change_table() yields a Table instance + # change_table(:suppliers) do |t| + # t.column :name, :string, :limit => 60 + # # Other column alterations here + # end + # + # ===== Examples + # ====== Add a column + # change_table(:suppliers) do |t| + # t.column :name, :string, :limit => 60 + # end + # + # ====== Add 2 integer columns + # change_table(:suppliers) do |t| + # t.integer :width, :height, :null => false, :default => 0 + # end + # + # ====== Add created_at/updated_at columns + # change_table(:suppliers) do |t| + # t.timestamps + # end + # + # ====== Add a foreign key column + # change_table(:suppliers) do |t| + # t.references :company + # end + # + # Creates a <tt>company_id(integer)</tt> column + # + # ====== Add a polymorphic foreign key column + # change_table(:suppliers) do |t| + # t.belongs_to :company, :polymorphic => true + # end + # + # Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns + # + # ====== Remove a column + # change_table(:suppliers) do |t| + # t.remove :company + # end + # + # ====== Remove a column + # change_table(:suppliers) do |t| + # t.remove :company_id + # t.remove :width, :height + # end + # + # ====== Remove an index + # change_table(:suppliers) do |t| + # t.remove_index :company_id + # end + # + # See also Table for details on + # all of the various column transformation + def change_table(table_name) + yield Table.new(table_name, self) + end + # Renames a table. # ===== Example # rename_table('octopuses', 'octopi') @@ -124,13 +185,17 @@ module ActiveRecord execute(add_column_sql) end - # Removes the column from the table definition. + # Removes the column(s) from the table definition. # ===== Examples # remove_column(:suppliers, :qualification) - def remove_column(table_name, column_name) - execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}" + # remove_columns(:suppliers, :qualification, :experience) + def remove_column(table_name, *column_names) + column_names.flatten.each do |column_name| + execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}" + end end - + alias :remove_columns :remove_column + # Changes the column's definition according to the new options. # See TableDefinition#column for details of the options you can use. # ===== Examples @@ -297,7 +362,14 @@ module ActiveRecord def add_column_options!(sql, options) #:nodoc: sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options) - sql << " NOT NULL" if options[:null] == false + # must explcitly check for :null to allow change_column to work on migrations + if options.has_key? :null + if options[:null] == false + sql << " NOT NULL" + else + sql << " NULL" + end + end end # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause. diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 6432c3cfee..e742d60c5f 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -196,7 +196,7 @@ module ActiveRecord :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", :string => { :name => "varchar", :limit => 255 }, :text => { :name => "text" }, - :integer => { :name => "int", :limit => 11 }, + :integer => { :name => "int"}, :float => { :name => "float" }, :decimal => { :name => "decimal" }, :datetime => { :name => "datetime" }, @@ -365,7 +365,7 @@ module ActiveRecord create_database(name) end - # Create a new MySQL database with optional :charset and :collation. + # Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>. # Charset defaults to utf8. # # Example: @@ -463,6 +463,22 @@ module ActiveRecord execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" end + # Maps logical Rails types to MySQL-specific data types. + def type_to_sql(type, limit = nil, precision = nil, scale = nil) + return super unless type.to_s == 'integer' + + case limit + when 0..3 + "smallint(#{limit})" + when 4..8 + "int(#{limit})" + when 9..20 + "bigint(#{limit})" + else + 'int(11)' + end + end + # SHOW VARIABLES LIKE 'name' def show_variable(name) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 54b50fabd8..e3f7969cdf 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -233,7 +233,7 @@ module ActiveRecord # * <tt>:username</tt> -- Defaults to nothing # * <tt>:password</tt> -- Defaults to nothing # * <tt>:database</tt> -- The name of the database. No default, must be provided. - # * <tt>:schema_search_path</tt> -- 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. + # * <tt>:schema_search_path</tt> -- An optional schema search path for the connection given as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option. # * <tt>:encoding</tt> -- An optional client encoding that is used in a SET client_encoding TO <encoding> call on the connection. # * <tt>:min_messages</tt> -- An optional client min messages that is used in a SET client_min_messages TO <min_messages> call on the connection. # * <tt>:allow_concurrency</tt> -- If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods. @@ -479,9 +479,9 @@ module ActiveRecord create_database(name) end - # Create a new PostgreSQL database. Options include :owner, :template, - # :encoding, :tablespace, and :connection_limit (note that MySQL uses - # :charset while PostgreSQL uses :encoding). + # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>, + # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses + # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>). # # Example: # create_database config[:database], config diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 59a51c0279..8fa62c1845 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -219,11 +219,14 @@ module ActiveRecord execute "VACUUM" end - def remove_column(table_name, column_name) #:nodoc: - alter_table(table_name) do |definition| - definition.columns.delete(definition[column_name]) + def remove_column(table_name, *column_names) #:nodoc: + column_names.flatten.each do |column_name| + alter_table(table_name) do |definition| + definition.columns.delete(definition[column_name]) + end end end + alias :remove_columns :remove_column def change_column_default(table_name, column_name, default) #:nodoc: alter_table(table_name) do |definition| diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index f5b2e73da9..7d5fd35dae 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -469,8 +469,8 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) fixtures.size > 1 ? fixtures : fixtures.first end - def self.cache_fixtures(connection, fixtures) - cache_for_connection(connection).update(fixtures.index_by { |f| f.table_name }) + def self.cache_fixtures(connection, fixtures_map) + cache_for_connection(connection).update(fixtures_map) end def self.instantiate_fixtures(object, table_name, fixtures, load_instances = true) @@ -526,7 +526,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) end end - cache_fixtures(connection, fixtures) + cache_fixtures(connection, fixtures_map) end end end diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index f2c2c5f070..65f88cfdc7 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -78,7 +78,7 @@ module ActiveRecord begin affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking") - UPDATE #{self.class.table_name} + UPDATE #{self.class.quoted_table_name} SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false, attribute_names))} WHERE #{self.class.primary_key} = #{quote_value(id)} AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)} diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb index caad760742..320659596f 100644 --- a/activerecord/lib/active_record/locking/pessimistic.rb +++ b/activerecord/lib/active_record/locking/pessimistic.rb @@ -25,12 +25,12 @@ module ActiveRecord # Locking::Pessimistic provides support for row-level locking using # SELECT ... FOR UPDATE and other lock types. # - # Pass :lock => true to ActiveRecord::Base.find to obtain an exclusive + # Pass <tt>:lock => true</tt> to ActiveRecord::Base.find to obtain an exclusive # lock on the selected rows: # # select * from accounts where id=1 for update # Account.find(1, :lock => true) # - # Pass :lock => 'some locking clause' to give a database-specific locking clause + # Pass <tt>:lock => 'some locking clause'</tt> to give a database-specific locking clause # of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'. # # Example: diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 1d63bb2f84..af4fb6e83c 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -76,16 +76,16 @@ module ActiveRecord # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+ to +new_name+. # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column to the table called +table_name+ # named +column_name+ specified to be one of the following types: - # :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, - # :date, :binary, :boolean. A default value can be specified by passing an - # +options+ hash like { :default => 11 }. Other options include :limit and :null (e.g. { :limit => 50, :null => false }) + # <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>, + # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be specified by passing an + # +options+ hash like <tt>{ :default => 11 }</tt>. Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g. <tt>{ :limit => 50, :null => false }</tt>) # -- see ActiveRecord::ConnectionAdapters::TableDefinition#column for details. # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames a column but keeps the type and content. # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes the column to a different type using the same # parameters as add_column. # * <tt>remove_column(table_name, column_name)</tt>: Removes the column named +column_name+ from the table called +table_name+. # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index with the name of the column. Other options include - # :name and :unique (e.g. { :name => "users_name_index", :unique => true }). + # <tt>:name</tt> and <tt>:unique</tt> (e.g. <tt>{ :name => "users_name_index", :unique => true }</tt>). # * <tt>remove_index(table_name, index_name)</tt>: Removes the index specified by +index_name+. # # == Irreversible transformations diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 120ec88f95..81b99f8e96 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -11,7 +11,6 @@ module ActiveRecord def self.included(base) base.class_eval do extend ClassMethods - named_scope :all named_scope :scoped, lambda { |scope| scope } end end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 3f11133e8c..61005af83f 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -45,7 +45,7 @@ module ActiveRecord end # Returns an array of AssociationReflection objects for all the associations in the class. If you only want to reflect on a - # certain association type, pass in the symbol (:has_many, :has_one, :belongs_to) for that as the first parameter. + # certain association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>, <tt>:belongs_to</tt>) for that as the first parameter. # Example: # # Account.reflect_on_all_associations # returns an array of all associations @@ -90,13 +90,12 @@ module ActiveRecord # Returns the hash of options used for the macro. For example, it would return <tt>{ :class_name => "Money" }</tt> for # <tt>composed_of :balance, :class_name => 'Money'</tt> or +{}+ for <tt>has_many :clients</tt>. - def options @options end - # Returns the class for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns the +Money+ - # class and <tt>has_many :clients</tt> returns the +Client+ class. + # Returns the class for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money + # class and <tt>has_many :clients</tt> returns the Client class. def klass @klass ||= class_name.constantize end @@ -158,16 +157,16 @@ module ActiveRecord @through_reflection ||= options[:through] ? active_record.reflect_on_association(options[:through]) : false end - # Gets an array of possible :through source reflection names + # Gets an array of possible <tt>:through</tt> source reflection names: # - # [singularized, pluralized] + # [:singularized, :pluralized] # def source_reflection_names @source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym } end - # Gets the source of the through reflection. It checks both a singularized and pluralized form for :belongs_to or :has_many. - # (The :tags association on Tagging below) + # Gets the source of the through reflection. It checks both a singularized and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>. + # (The <tt>:tags</tt> association on Tagging below.) # # class Post # has_many :tags, :through => :taggings diff --git a/activerecord/lib/active_record/serialization.rb b/activerecord/lib/active_record/serialization.rb index 2c8210a299..332cda1e16 100644 --- a/activerecord/lib/active_record/serialization.rb +++ b/activerecord/lib/active_record/serialization.rb @@ -8,11 +8,11 @@ module ActiveRecord #:nodoc: end # To replicate the behavior in ActiveRecord#attributes, - # :except takes precedence over :only. If :only is not set + # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set # for a N level model but is set for the N+1 level models, - # then because :except is set to a default value, the second - # level model can have both :except and :only set. So if - # :only is set, always delete :except. + # then because <tt>:except</tt> is set to a default value, the second + # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if + # <tt>:only</tt> is set, always delete <tt>:except</tt>. def serializable_attribute_names attribute_names = @record.attribute_names @@ -38,7 +38,7 @@ module ActiveRecord #:nodoc: serializable_attribute_names + serializable_method_names end - # Add associations specified via the :includes option. + # Add associations specified via the <tt>:includes</tt> option. # Expects a block that takes as arguments: # +association+ - name of the association # +records+ - the association record(s) to be serialized diff --git a/activerecord/lib/active_record/serializers/json_serializer.rb b/activerecord/lib/active_record/serializers/json_serializer.rb index d024adba39..419b45d475 100644 --- a/activerecord/lib/active_record/serializers/json_serializer.rb +++ b/activerecord/lib/active_record/serializers/json_serializer.rb @@ -16,8 +16,8 @@ module ActiveRecord #:nodoc: # # => {"id": 1, "name": "Konata Izumi", "age": 16, # "created_at": "2006/08/01", "awesome": true} # - # The :only and :except options can be used to limit the attributes - # included, and work similar to the #attributes method. For example: + # The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the attributes + # included, and work similar to the +attributes+ method. For example: # # konata.to_json(:only => [ :id, :name ]) # # => {"id": 1, "name": "Konata Izumi"} @@ -25,14 +25,14 @@ module ActiveRecord #:nodoc: # konata.to_json(:except => [ :id, :created_at, :age ]) # # => {"name": "Konata Izumi", "awesome": true} # - # To include any methods on the model, use :methods. + # To include any methods on the model, use <tt>:methods</tt>. # # konata.to_json(:methods => :permalink) # # => {"id": 1, "name": "Konata Izumi", "age": 16, # "created_at": "2006/08/01", "awesome": true, # "permalink": "1-konata-izumi"} # - # To include associations, use :include. + # To include associations, use <tt>:include</tt>. # # konata.to_json(:include => :posts) # # => {"id": 1, "name": "Konata Izumi", "age": 16, diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index fbd15e06dc..2d0887ecf0 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -2,7 +2,7 @@ module ActiveRecord #:nodoc: module Serialization # Builds an XML document to represent the model. Some configuration is # available through +options+. However more complicated cases should - # override ActiveRecord's to_xml method. + # override ActiveRecord::Base#to_xml. # # By default the generated XML document will include the processing # instruction and all the object's attributes. For example: @@ -22,12 +22,12 @@ module ActiveRecord #:nodoc: # <last-read type="date">2004-04-15</last-read> # </topic> # - # This behavior can be controlled with :only, :except, - # :skip_instruct, :skip_types and :dasherize. The :only and - # :except options are the same as for the #attributes method. - # The default is to dasherize all column names, to disable this, - # set :dasherize to false. To not have the column type included - # in the XML output, set :skip_types to true. + # This behavior can be controlled with <tt>:only</tt>, <tt>:except</tt>, + # <tt>:skip_instruct</tt>, <tt>:skip_types</tt> and <tt>:dasherize</tt>. + # The <tt>:only</tt> and <tt>:except</tt> options are the same as for the + # +attributes+ method. The default is to dasherize all column names, but you + # can disable this setting <tt>:dasherize</tt> to +false+. To not have the + # column type included in the XML output set <tt>:skip_types</tt> to +true+. # # For instance: # @@ -43,7 +43,7 @@ module ActiveRecord #:nodoc: # <last-read type="date">2004-04-15</last-read> # </topic> # - # To include first level associations use :include + # To include first level associations use <tt>:include</tt>: # # firm.to_xml :include => [ :account, :clients ] # @@ -98,7 +98,7 @@ module ActiveRecord #:nodoc: # </account> # </firm> # - # To include any methods on the object(s) being called use :methods + # To include any methods on the model being called use <tt>:methods</tt>: # # firm.to_xml :methods => [ :calculated_earnings, :real_earnings ] # @@ -108,9 +108,8 @@ module ActiveRecord #:nodoc: # <real-earnings>5</real-earnings> # </firm> # - # To call any Procs on the object(s) use :procs. The Procs - # are passed a modified version of the options hash that was - # given to #to_xml. + # To call any additional Procs use <tt>:procs</tt>. The Procs are passed a + # modified version of the options hash that was given to +to_xml+: # # proc = Proc.new { |options| options[:builder].tag!('abc', 'def') } # firm.to_xml :procs => [ proc ] @@ -120,7 +119,7 @@ module ActiveRecord #:nodoc: # <abc>def</abc> # </firm> # - # Alternatively, you can yield the builder object as part of the to_xml call: + # Alternatively, you can yield the builder object as part of the +to_xml+ call: # # firm.to_xml do |xml| # xml.creator do @@ -137,8 +136,9 @@ module ActiveRecord #:nodoc: # </creator> # </firm> # - # You can override the to_xml method in your ActiveRecord::Base - # subclasses if you need to. The general form of doing this is: + # As noted above, you may override +to_xml+ in your ActiveRecord::Base + # subclasses to have complete control about what's generated. The general + # form of doing this is: # # class IHaveMyOwnXML < ActiveRecord::Base # def to_xml(options = {}) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 1d12ea8ad7..50db32725d 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -201,7 +201,7 @@ module ActiveRecord alias_method :count, :size alias_method :length, :size - # Return an XML representation of this error object. + # Returns an XML representation of this error object. # # class Company < ActiveRecord::Base # validates_presence_of :name, :address, :email @@ -266,7 +266,7 @@ module ActiveRecord # person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" } # person.save # => true (and person is now saved in the database) # - # An +Errors+ object is automatically created for every Active Record. + # An Errors object is automatically created for every Active Record. # # Please do have a look at ActiveRecord::Validations::ClassMethods for a higher level of validations. module Validations @@ -286,7 +286,7 @@ module ActiveRecord # All of the following validations are defined in the class scope of the model that you're interested in validating. # They offer a more declarative way of specifying when the model is valid and when it is not. It is recommended to use - # these over the low-level calls to validate and validate_on_create when possible. + # these over the low-level calls to +validate+ and +validate_on_create+ when possible. module ClassMethods DEFAULT_VALIDATION_OPTIONS = { :on => :save, @@ -337,14 +337,14 @@ module ActiveRecord # end # # Options: - # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update) - # * <tt>allow_nil</tt> - Skip validation if attribute is nil. - # * <tt>allow_blank</tt> - Skip validation if attribute is blank. - # * <tt>if</tt> - 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 + # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). + # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+. + # * <tt>:allow_blank</tt> - Skip validation if attribute is blank. + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_each(*attrs) options = attrs.extract_options!.symbolize_keys @@ -374,19 +374,19 @@ module ActiveRecord # # The added +password_confirmation+ attribute is virtual; it exists only as an in-memory attribute for validating the password. # To achieve this, the validation adds accessors to the model for the confirmation attribute. NOTE: This check is performed - # only if +password_confirmation+ is not nil, and by default only on save. To require confirmation, make sure to add a presence + # only if +password_confirmation+ is not +nil+, and by default only on save. To require confirmation, make sure to add a presence # check for the confirmation attribute: # # validates_presence_of :password_confirmation, :if => :password_changed? # # Configuration options: - # * <tt>message</tt> - A custom error message (default is: "doesn't match confirmation") - # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update) - # * <tt>if</tt> - 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 + # * <tt>:message</tt> - A custom error message (default is: "doesn't match confirmation"). + # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_confirmation_of(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save } @@ -406,21 +406,21 @@ module ActiveRecord # validates_acceptance_of :eula, :message => "must be abided" # end # - # If the database column does not exist, the terms_of_service attribute is entirely virtual. This check is - # performed only if terms_of_service is not nil and by default on save. + # If the database column does not exist, the +terms_of_service+ attribute is entirely virtual. This check is + # performed only if +terms_of_service+ is not +nil+ and by default on save. # # Configuration options: - # * <tt>message</tt> - A custom error message (default is: "must be accepted") - # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update) - # * <tt>allow_nil</tt> - Skip validation if attribute is nil. (default is true) - # * <tt>accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which - # makes it easy to relate to an HTML checkbox. This should be set to 'true' if you are validating a database - # column, since the attribute is typecast from "1" to <tt>true</tt> before validation. - # * <tt>if</tt> - 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 + # * <tt>:message</tt> - A custom error message (default is: "must be accepted"). + # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). + # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is true). + # * <tt>:accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which + # makes it easy to relate to an HTML checkbox. This should be set to +true+ if you are validating a database + # column, since the attribute is typecast from "1" to +true+ before validation. + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_acceptance_of(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" } @@ -452,8 +452,8 @@ module ActiveRecord # This is due to the way Object#blank? handles boolean values. false.blank? # => true # # Configuration options: - # * <tt>message</tt> - A custom error message (default is: "can't be blank") - # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update) + # * <tt>message</tt> - A custom error message (default is: "can't be blank"). + # * <tt>on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). # * <tt>if</tt> - 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. @@ -485,24 +485,24 @@ module ActiveRecord # end # # Configuration options: - # * <tt>minimum</tt> - The minimum size of the attribute - # * <tt>maximum</tt> - The maximum size of the attribute - # * <tt>is</tt> - The exact size of the attribute - # * <tt>within</tt> - A range specifying the minimum and maximum size of the attribute - # * <tt>in</tt> - A synonym(or alias) for :within - # * <tt>allow_nil</tt> - Attribute may be nil; skip validation. - # * <tt>allow_blank</tt> - Attribute may be blank; skip validation. - # - # * <tt>too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)") - # * <tt>too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)") - # * <tt>wrong_length</tt> - The error message if using the :is method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)") - # * <tt>message</tt> - The error message to use for a :minimum, :maximum, or :is violation. An alias of the appropriate too_long/too_short/wrong_length message - # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update) - # * <tt>if</tt> - 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 + # * <tt>:minimum</tt> - The minimum size of the attribute. + # * <tt>:maximum</tt> - The maximum size of the attribute. + # * <tt>:is</tt> - The exact size of the attribute. + # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute. + # * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>. + # * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation. + # * <tt>:allow_blank</tt> - Attribute may be blank; skip validation. + # + # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)"). + # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)"). + # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)"). + # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message. + # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_length_of(*attrs) # Merge given options with defaults. @@ -584,16 +584,16 @@ module ActiveRecord # unique index on the field. See +add_index+ for more information. # # Configuration options: - # * <tt>message</tt> - Specifies a custom error message (default is: "has already been taken") - # * <tt>scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint. - # * <tt>case_sensitive</tt> - Looks for an exact match. Ignored by non-text columns (true by default). - # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false) - # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false) - # * <tt>if</tt> - 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 + # * <tt>:message</tt> - Specifies a custom error message (default is: "has already been taken"). + # * <tt>:scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint. + # * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by non-text columns (+false+ by default). + # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+). + # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+). + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_uniqueness_of(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken], :case_sensitive => true } @@ -669,21 +669,21 @@ module ActiveRecord # validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create # end # - # Note: use \A and \Z to match the start and end of the string, ^ and $ match the start/end of a line. + # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line. # # A regular expression must be provided or else an exception will be raised. # # Configuration options: - # * <tt>message</tt> - A custom error message (default is: "is invalid") - # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false) - # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false) - # * <tt>with</tt> - The regular expression used to validate the format with (note: must be supplied!) - # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update) - # * <tt>if</tt> - 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 + # * <tt>:message</tt> - A custom error message (default is: "is invalid"). + # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+). + # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+). + # * <tt>:with</tt> - The regular expression used to validate the format with (note: must be supplied!). + # * <tt>:on</tt> Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_format_of(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil } @@ -705,15 +705,15 @@ module ActiveRecord # end # # Configuration options: - # * <tt>in</tt> - An enumerable object of available items - # * <tt>message</tt> - Specifies a custom error message (default is: "is not included in the list") - # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false) - # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false) - # * <tt>if</tt> - 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 + # * <tt>:in</tt> - An enumerable object of available items. + # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list"). + # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+). + # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+). + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_inclusion_of(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save } @@ -737,15 +737,15 @@ module ActiveRecord # end # # Configuration options: - # * <tt>in</tt> - An enumerable object of items that the value shouldn't be part of - # * <tt>message</tt> - Specifies a custom error message (default is: "is reserved") - # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false) - # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false) - # * <tt>if</tt> - 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 + # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of. + # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved"). + # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+). + # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+). + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_exclusion_of(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save } @@ -777,19 +777,19 @@ module ActiveRecord # validates_associated :book # end # - # ...this would specify a circular dependency and cause infinite recursion. + # 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. + # is both present and guaranteed to be valid, you also need to use +validates_presence_of+. # # Configuration options: - # * <tt>message</tt> - A custom error message (default is: "is invalid") - # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update) - # * <tt>if</tt> - 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 + # * <tt>:message</tt> - A custom error message (default is: "is invalid") + # * <tt>:on</tt> Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>) + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_associated(*attr_names) configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save } @@ -810,22 +810,22 @@ module ActiveRecord # end # # Configuration options: - # * <tt>message</tt> - A custom error message (default is: "is not a number") - # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update) - # * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false) - # * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float columns empty strings are converted to nil - # * <tt>greater_than</tt> Specifies the value must be greater than the supplied value - # * <tt>greater_than_or_equal_to</tt> Specifies the value must be greater than or equal the supplied value - # * <tt>equal_to</tt> Specifies the value must be equal to the supplied value - # * <tt>less_than</tt> Specifies the value must be less than the supplied value - # * <tt>less_than_or_equal_to</tt> Specifies the value must be less than or equal the supplied value - # * <tt>odd</tt> Specifies the value must be an odd number - # * <tt>even</tt> Specifies the value must be an even number - # * <tt>if</tt> - 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 + # * <tt>:message</tt> - A custom error message (default is: "is not a number"). + # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>). + # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+). + # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+. + # * <tt>:greater_than</tt> - Specifies the value must be greater than the supplied value. + # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater than or equal the supplied value. + # * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value. + # * <tt>:less_than</tt> - Specifies the value must be less than the supplied value. + # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or equal the supplied value. + # * <tt>:odd</tt> - Specifies the value must be an odd number. + # * <tt>:even</tt> - Specifies the value must be an even number. + # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should + # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. - # * <tt>unless</tt> - 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 + # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should + # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a true or false value. def validates_numericality_of(*attr_names) configuration = { :on => :save, :only_integer => false, :allow_nil => false } @@ -873,11 +873,12 @@ module ActiveRecord # Creates an object just like Base.create but calls save! instead of save # so an exception is raised if the record is invalid. - def create!(attributes = nil) + def create!(attributes = nil, &block) if attributes.is_a?(Array) - attributes.collect { |attr| create!(attr) } + attributes.collect { |attr| create!(attr, &block) } else object = new(attributes) + yield(object) if block_given? object.save! object end @@ -921,7 +922,7 @@ module ActiveRecord save(false) end - # Runs validate and validate_on_create or validate_on_update and returns true if no errors were added otherwise false. + # Runs +validate+ and +validate_on_create+ or +validate_on_update+ and returns true if no errors were added otherwise false. def valid? errors.clear @@ -945,7 +946,7 @@ module ActiveRecord end protected - # Overwrite this method for validation checks on all saves and use Errors.add(field, msg) for invalid attributes. + # Overwrite this method for validation checks on all saves and use <tt>Errors.add(field, msg)</tt> for invalid attributes. def validate #:doc: end |