diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 741649f..7388a6e 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -613,24 +613,26 @@ module ActiveRecord class_hierarchy.insert(0, class_hierarchy.first.superclass) end + quoted_attr_name = connection.quote_column_name(attr_name) + # Now we can work our way down the tree to the first non-abstract # class (which has a database table to query from). finder_class = class_hierarchy.detect { |klass| !klass.abstract_class? } if value.nil? || (configuration[:case_sensitive] || !finder_class.columns_hash[attr_name.to_s].text?) - condition_sql = "#{record.class.quoted_table_name}.#{attr_name} #{attribute_condition(value)}" + condition_sql = "#{record.class.quoted_table_name}.#{quoted_attr_name} #{attribute_condition(value)}" 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(#{record.class.quoted_table_name}.#{quoted_attr_name}) #{attribute_condition(value)}" 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_sql << " AND #{record.class.quoted_table_name}.#{connection.quote_column_name(scope_item)} #{attribute_condition(scope_value)}" condition_params << scope_value end end @@ -643,7 +645,7 @@ module ActiveRecord results = finder_class.with_exclusive_scope do connection.select_all( construct_finder_sql( - :select => "#{connection.quote_column_name(attr_name)}", + :select => "#{quoted_attr_name}", :from => "#{finder_class.quoted_table_name}", :conditions => [condition_sql, *condition_params] ) diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 60566cd..d0efcac 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -31,6 +31,10 @@ class UniqueReply < Reply validates_uniqueness_of :content, :scope => 'parent_id' end +class UniqueTopicOn < Topic + validates_uniqueness_of :on +end + class PlagiarizedReply < Reply validates_acceptance_of :author_name end @@ -73,6 +77,15 @@ class ValidationsTest < ActiveRecord::TestCase assert r.valid?, "A reply with content should be saveable" end + def test_columns_get_quoted_on_unique_validation + t = UniqueTopicOn.new( "title" => "tender", + "content" => "love", + "on" => Date.today ) + assert_nothing_raised { + assert t.valid? + } + end + def test_single_attr_validation_and_error_msg r = Reply.new r.title = "There's no content!" diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 29c91a4..300eb43 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -371,6 +371,7 @@ ActiveRecord::Schema.define do t.boolean :approved, :default => true t.integer :replies_count, :default => 0 t.integer :parent_id + t.date :on t.string :type end