diff options
Diffstat (limited to 'activerecord')
4 files changed, 32 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index be0af081d1..01d25b8867 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -28,7 +28,7 @@ module ActiveRecord # Association with autosave option defines several callbacks on your # model (before_save, after_create, after_update). Please note that # callbacks are executed in the order they were defined in - # model. You should avoid modyfing the association content, before + # model. You should avoid modifying the association content, before # autosave callbacks are executed. Placing your callbacks after # associations is usually a good practice. # diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 9556878f63..db618f617f 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -35,8 +35,14 @@ module ActiveRecord relation = relation.and(table[scope_item].eq(scope_value)) end - if finder_class.unscoped.where(relation).exists? - record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value)) + relation = finder_class.unscoped.where(relation) + + if options[:conditions] + relation = relation.merge(options[:conditions]) + end + + if relation.exists? + record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope, :conditions).merge(:value => value)) end end @@ -102,6 +108,14 @@ module ActiveRecord # validates_uniqueness_of :teacher_id, :scope => [:semester_id, :class_id] # end # + # It is also possible to limit the uniqueness constraint to a set of records matching certain conditions. + # In this example archived articles are not being taken into consideration when validating uniqueness + # of the title attribute: + # + # class Article < ActiveRecord::Base + # validates_uniqueness_of :title, :conditions => where('status != ?', 'archived') + # 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. @@ -109,6 +123,8 @@ module ActiveRecord # 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>:conditions</tt> - Specify the conditions to be included as a <tt>WHERE</tt> SQL fragment to limit + # the uniqueness constraint lookup. (e.g. <tt>:conditions => where('status = ?', 'active')</tt>) # * <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 +nil+ (default is +false+). # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+). diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 63d47f5162..3edc237c44 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1238,7 +1238,7 @@ class RelationTest < ActiveRecord::TestCase def test_presence topics = Topic.scoped - # the fist query is triggered because there are no topics yet. + # the first query is triggered because there are no topics yet. assert_queries(1) { assert topics.present? } # checking if there are topics is used before you actually display them, diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index 79442d68b0..376c0000c7 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -325,4 +325,16 @@ class UniquenessValidationTest < ActiveRecord::TestCase assert w6.errors[:city].any?, "Should have errors for city" assert_equal ["has already been taken"], w6.errors[:city], "Should have uniqueness message for city" end + + def test_validate_uniqueness_with_conditions + Topic.validates_uniqueness_of(:title, :conditions => Topic.where('approved = ?', true)) + t1 = Topic.create("title" => "I'm a topic", "approved" => true) + t2 = Topic.create("title" => "I'm an unapproved topic", "approved" => false) + + t3 = Topic.new("title" => "I'm a topic", "approved" => true) + assert !t3.valid?, "t3 shouldn't be valid" + + t4 = Topic.new("title" => "I'm an unapproved topic", "approved" => false) + assert t4.valid?, "t4 should be valid" + end end |