vendor/rails/activerecord/lib/active_record/validations.rb
# 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.
#
#   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.
#
# Because this check is performed outside the database there is still a chance that duplicate values
# will be inserted in two parallel transactions.  To guarantee against this you should create a
# 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 (+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. <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.
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".



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.



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.

Because this check is performed outside the database there is still a chance that duplicate values
will be inserted in two parallel transactions.  To guarantee against this you should create a
unique index on the field. See +add_index+ for more information.

Configuration options:
:message - Specifies a custom error message (default is: "has already been taken").
:scope - One or more columns by which to limit the scope of the uniqueness constraint.
:case_sensitive - Looks for an exact match.  Ignored by non-text columns (+false+ by default).
: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 .  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 .  The
method, proc or string should return or evaluate to a true or false value.
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 " . 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 . 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 . Because this check is performed outside the database there is still a chance that duplicate values will be inserted in two parallel transactions . To guarantee against this you should create a unique index on the field . See + add_index + for more information . Configuration options : : message - Specifies a custom error message ( default is : " has already been taken " ) . : scope - One or more columns by which to limit the scope of the uniqueness constraint . : case_sensitive - Looks for an exact match . Ignored by non - text columns ( + false + by default ) . : 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 . 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 . The method proc or string should return or evaluate to a true or false value .
def validates_uniqueness_of(*attr_names)
        configuration = { :case_sensitive => true }
        configuration.update(attr_names.extract_options!)
        validates_each(attr_names,configuration) do |record, attr_name, value|
          class_hierarchy = [record.class]
          while class_hierarchy.first != self
            class_hierarchy.insert(0, class_hierarchy.first.superclass)
          end
          finder_class = class_hierarchy.detect { |klass| !klass.abstract_class? }
          is_text_column = finder_class.columns_hash[attr_name.to_s].text?
          if value.nil?
            comparison_operator = "IS ?"
          elsif is_text_column
            comparison_operator = "#{connection.case_sensitive_equality_operator} ?"
            value = value.to_s
          else
            comparison_operator = "= ?"
          end
          sql_attribute = "#{record.class.quoted_table_name}.#{connection.quote_column_name(attr_name)}"
          if value.nil? || (configuration[:case_sensitive] || !is_text_column)
            condition_sql = "#{sql_attribute} #{comparison_operator}"
            condition_params = [value]
          else
            condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}"
            condition_params = [value.downcase]
          end
          if scope = configuration[:scope]
            Array(scope).map do |scope_item|
              scope_value = record.send(scope_item)
              condition_sql << " AND #{record.class.quoted_table_name}.#{scope_item} #{attribute_condition(scope_value)}"
              condition_params << scope_value
            end
          end
          unless record.new_record?
            condition_sql << " AND #{record.class.quoted_table_name}.#{record.class.primary_key} <> ?"
            condition_params << record.send(:id)
          end
          finder_class.with_exclusive_scope do
            if finder_class.exists?([condition_sql, *condition_params])
              record.errors.add(attr_name, :taken, :default => configuration[:message], :value => value)
            end
          end
        end
      end
def validates_uniqueness_of ( * attr_names ) configuration = { :case_sensitive => true } configuration . update ( attr_names . extract_options! ) validates_each ( attr_names , configuration ) do | record , attr_name , value | class_hierarchy = [ record . class ] while class_hierarchy . first != self class_hierarchy . insert ( 0 , class_hierarchy . first . superclass ) end finder_class = class_hierarchy . detect { | klass | ! klass . abstract_class? } is_text_column = finder_class . columns_hash [ attr_name . to_s ] . text? if value . nil? comparison_operator = "IS ?" elsif is_text_column comparison_operator = "#{connection.case_sensitive_equality_operator} ?" value = value . to_s else comparison_operator = "= ?" end sql_attribute = "#{record.class.quoted_table_name}.#{connection.quote_column_name(attr_name)}" if value . nil? || ( configuration [ :case_sensitive ] || ! is_text_column ) condition_sql = "#{sql_attribute} #{comparison_operator}" condition_params = [ value ] else condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}" condition_params = [ value . downcase ] end if scope = configuration [ :scope ] Array ( scope ) . map do | scope_item | scope_value = record . send ( scope_item ) condition_sql << " AND #{record.class.quoted_table_name}.#{scope_item} #{attribute_condition(scope_value)}" condition_params << scope_value end end unless record . new_record? condition_sql << " AND #{record.class.quoted_table_name}.#{record.class.primary_key} <> ?" condition_params << record . send ( :id ) end finder_class . with_exclusive_scope do if finder_class . exists? ( [ condition_sql , * condition_params ] ) record . errors . add ( attr_name , :taken , :default => configuration [ :message ] , :value => value ) end end end end
Validates whether the value of the specified attributes are unique across the system.
Validates whether the value of the specified attributes are unique across the system .
# The check for an existing value should be run from a class that # isn't abstract. This means working down from the current class # (self), to the first non-abstract class. Since classes don't know # their subclasses, we have to build the hierarchy between self and # the record's class. # Now we can work our way down the tree to the first non-abstract # class (which has a database table to query from).
attr_names