Skip to content

Commit

Permalink
validates_uniqueness_of uses database case sensitivity support instea…
Browse files Browse the repository at this point in the history
…d of using ruby

Signed-off-by: Michael Koziarski <michael@koziarski.com>
  • Loading branch information
tarmo authored and NZKoz committed Jul 31, 2008
1 parent f3da46e commit f7eaab9
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 27 deletions.
Expand Up @@ -149,6 +149,10 @@ def empty_insert_statement(table_name)
"INSERT INTO #{quote_table_name(table_name)} VALUES(DEFAULT)"
end

def case_sensitive_equality_operator
"="
end

protected
# Returns an array of record hashes with the column names as keys and
# column values as values.
Expand Down
Expand Up @@ -511,6 +511,10 @@ def pk_and_sequence_for(table) #:nodoc:
keys.length == 1 ? [keys.first, nil] : nil
end

def case_sensitive_equality_operator
"= BINARY"
end

private
def connect
@connection.reconnect = true if @connection.respond_to?(:reconnect=)
Expand Down
42 changes: 15 additions & 27 deletions activerecord/lib/active_record/validations.rb
Expand Up @@ -627,17 +627,23 @@ def validates_uniqueness_of(*attr_names)

is_text_column = finder_class.columns_hash[attr_name.to_s].text?

if !value.nil? && is_text_column
value = value.to_s
if value.nil?
comparison_operator = "IS ?"
else
comparison_operator = "#{connection.case_sensitive_equality_operator} ?"

if is_text_column
value = value.to_s
end
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 = "#{record.class.quoted_table_name}.#{attr_name} #{attribute_condition(value)}"
condition_sql = "#{sql_attribute} #{comparison_operator}"
condition_params = [value]
else
# sqlite has case sensitive SELECT query, while MySQL/Postgresql don't.
# Hence, this is needed only for sqlite.
condition_sql = "LOWER(#{record.class.quoted_table_name}.#{attr_name}) #{attribute_condition(value)}"
condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}"
condition_params = [value.downcase]
end

Expand All @@ -654,28 +660,10 @@ def validates_uniqueness_of(*attr_names)
condition_params << record.send(:id)
end

results = finder_class.with_exclusive_scope do
connection.select_all(
construct_finder_sql(
:select => "#{connection.quote_column_name(attr_name)}",
:from => "#{finder_class.quoted_table_name}",
:conditions => [condition_sql, *condition_params]
)
)
end

unless results.length.zero?
found = true

# As MySQL/Postgres don't have case sensitive SELECT queries, we try to find duplicate
# column in ruby when case sensitive option
if configuration[:case_sensitive] && finder_class.columns_hash[attr_name.to_s].text?
found = results.any? { |a| a[attr_name.to_s] == value.to_s }
end

if found
finder_class.with_exclusive_scope do
if finder_class.exists?([condition_sql, *condition_params])
message = record.errors.generate_message(attr_name, :taken, :default => configuration[:message])
record.errors.add(attr_name, message)
record.errors.add(attr_name, message)
end
end
end
Expand Down

1 comment on commit f7eaab9

@trevorturk
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet!

Please sign in to comment.