1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Allow validate_uniqueness_of to be scoped by more than just one column. Closes #1559.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3206 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
Marcel Molina 2005-12-02 04:30:46 +00:00
parent 3d0e3c9290
commit 2e42167058
3 changed files with 41 additions and 5 deletions

View file

@ -1,5 +1,7 @@
*SVN*
* Allow validate_uniqueness_of to be scoped by more than just one column. #1559. [jeremy@jthopple.com, Marcel Molina Jr.]
* Firebird: active? and reconnect! methods for handling stale connections. #428 [Ken Kunz <kennethkunz@gmail.com>]
* Firebird: updated for FireRuby 0.4.0. #3009 [Ken Kunz <kennethkunz@gmail.com>]

View file

@ -471,7 +471,14 @@ module ActiveRecord
# can be named "davidhh".
#
# class Person < ActiveRecord::Base
# validates_uniqueness_of :user_name, :scope => "account_id"
# 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
@ -479,10 +486,11 @@ module ActiveRecord
#
# Configuration options:
# * <tt>message</tt> - Specifies a custom error message (default is: "has already been taken")
# * <tt>scope</tt> - Ensures that the uniqueness is restricted to a condition of "scope = record.scope"
# * <tt>scope</tt> - One or more columns by which to limit the scope of the uniquness constraint.
# * <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.
def validates_uniqueness_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken] }
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
@ -491,9 +499,11 @@ module ActiveRecord
condition_sql = "#{attr_name} #{attribute_condition(value)}"
condition_params = [value]
if scope = configuration[:scope]
scope_value = record.send(scope)
condition_sql << " AND #{scope} #{attribute_condition(scope_value)}"
condition_params << scope_value
Array(scope).map do |scope_item|
scope_value = record.send(scope_item)
condition_sql << " AND #{scope_item} #{attribute_condition(scope_value)}"
condition_params << scope_value
end
end
unless record.new_record?
condition_sql << " AND #{record.class.primary_key} <> ?"

View file

@ -280,6 +280,30 @@ class ValidationsTest < Test::Unit::TestCase
assert r3.valid?, "Saving r3"
end
def test_validate_uniqueness_with_scope_array
Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
t = Topic.create("title" => "The earth is actually flat!")
r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
assert r1.valid?, "Saving r1"
r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
assert !r2.valid?, "Saving r2. Double reply by same author."
r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
assert r2.save, "Saving r2 the second time."
r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
assert !r3.valid?, "Saving r3"
r3.author_name = "jj"
assert r3.save, "Saving r3 the second time."
r3.author_name = "jeremy"
assert !r3.save, "Saving r3 the third time."
end
def test_validate_format
Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")