Created
May 13, 2011 03:23
-
-
Save AquaGeek/969909 to your computer and use it in GitHub Desktop.
Rails Lighthouse ticket #873
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From a30e32aab00f9f1497e25361217399490bc01ec8 Mon Sep 17 00:00:00 2001 | |
From: Sean Huber <[email protected]> | |
Date: Wed, 20 Aug 2008 11:29:55 -0700 | |
Subject: [PATCH] validates_exclusion_of can now accept a symbol representing an instance method or a proc object as the :in/:within option | |
--- | |
.../lib/active_model/validations/exclusion.rb | 25 +++++++++++++-- | |
activerecord/lib/active_record/validations.rb | 31 +++++++++++++++---- | |
activerecord/test/cases/validations_test.rb | 31 ++++++++++++++++++++ | |
3 files changed, 76 insertions(+), 11 deletions(-) | |
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb | |
index f3367ab..1a4dd87 100644 | |
--- a/activemodel/lib/active_model/validations/exclusion.rb | |
+++ b/activemodel/lib/active_model/validations/exclusion.rb | |
@@ -5,12 +5,20 @@ module ActiveModel | |
# | |
# class Person < ActiveRecord::Base | |
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here" | |
+ # validates_exclusion_of :username, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_exclusion_of :username, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60" | |
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %s is not allowed" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( admin superuser ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of | |
+ # * <tt>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of items that the value shouldn't be part of | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
# * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved") | |
# * <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+) | |
@@ -26,10 +34,19 @@ module ActiveModel | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- record.errors.add(attr_name, configuration[:message] % value) if enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ record.errors.add(attr_name, configuration[:message] % value) if enum_object.include?(value) | |
end | |
end | |
end | |
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb | |
index b7e6394..7b0d188 100644 | |
--- a/activerecord/lib/active_record/validations.rb | |
+++ b/activerecord/lib/active_record/validations.rb | |
@@ -745,15 +745,23 @@ module ActiveRecord | |
# | |
# class Person < ActiveRecord::Base | |
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here" | |
+ # validates_exclusion_of :username, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_exclusion_of :username, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60" | |
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %s is not allowed" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( admin superuser ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of. | |
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved"). | |
- # * <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>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of items that the value shouldn't be part of | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved") | |
+ # * <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. | |
@@ -766,10 +774,19 @@ module ActiveRecord | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- if enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ if enum_object.include?(value) | |
message = record.errors.generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value) | |
record.errors.add(attr_name, message) | |
end | |
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb | |
index 4b2d28c..5899a84 100644 | |
--- a/activerecord/test/cases/validations_test.rb | |
+++ b/activerecord/test/cases/validations_test.rb | |
@@ -688,6 +688,37 @@ class ValidationsTest < ActiveRecord::TestCase | |
assert t.errors.on(:title) | |
assert_equal "option monkey is restricted", t.errors["title"] | |
end | |
+ | |
+ def test_validates_exclusion_of_with_proc_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => Proc.new { |topic| [topic.class.to_s] } ) | |
+ | |
+ assert Topic.create("title" => "something", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "Topic", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_exclusion_of_with_symbol_enumerable | |
+ Topic.class_eval "def title_exclusions; ['test']; end" | |
+ | |
+ Topic.validates_exclusion_of( :title, :in => :title_exclusions ) | |
+ | |
+ assert Topic.create("title" => "something", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "test", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_exclusion_of_should_raise_argument_error_if_in_option_is_not_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => nil ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_exclusion_of_should_raise_argument_error_if_in_option_is_a_symbol_and_is_not_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => :new_record? ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_exclusion_of_should_raise_argument_error_if_in_option_is_a_proc_and_is_not_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => Proc.new { |topic| nil } ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
def test_validates_length_of_using_minimum | |
Topic.validates_length_of :title, :minimum => 5 | |
-- | |
1.5.4.3 | |
From e9b9a481e48f172630a796ba2ac2e6b5e54e0e0b Mon Sep 17 00:00:00 2001 | |
From: Sean Huber <[email protected]> | |
Date: Wed, 20 Aug 2008 11:46:24 -0700 | |
Subject: [PATCH] validates_inclusion_of can now accept a symbol representing an instance method or a proc object as the :in/:within option | |
--- | |
.../lib/active_model/validations/inclusion.rb | 25 +++++++++++-- | |
activerecord/lib/active_record/validations.rb | 31 ++++++++++++---- | |
activerecord/test/cases/validations_test.rb | 38 ++++++++++++++++++++ | |
3 files changed, 83 insertions(+), 11 deletions(-) | |
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb | |
index 9fc1caa..6c1eabe 100644 | |
--- a/activemodel/lib/active_model/validations/inclusion.rb | |
+++ b/activemodel/lib/active_model/validations/inclusion.rb | |
@@ -5,12 +5,20 @@ module ActiveModel | |
# | |
# class Person < ActiveRecord::Base | |
# validates_inclusion_of :gender, :in => %w( m f ), :message => "woah! what are you then!??!!" | |
+ # validates_inclusion_of :gender, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_inclusion_of :gender, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_inclusion_of :age, :in => 0..99 | |
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %s is not included in the list" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( m f ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of available items | |
+ # * <tt>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of available items | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
# * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list") | |
# * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is null (default is: +false+) | |
# * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the attribute is blank (default is: +false+) | |
@@ -26,10 +34,19 @@ module ActiveModel | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- record.errors.add(attr_name, configuration[:message] % value) unless enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ record.errors.add(attr_name, configuration[:message] % value) unless enum_object.include?(value) | |
end | |
end | |
end | |
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb | |
index 7b0d188..0a3a00e 100644 | |
--- a/activerecord/lib/active_record/validations.rb | |
+++ b/activerecord/lib/active_record/validations.rb | |
@@ -710,15 +710,23 @@ module ActiveRecord | |
# | |
# class Person < ActiveRecord::Base | |
# validates_inclusion_of :gender, :in => %w( m f ), :message => "woah! what are you then!??!!" | |
+ # validates_inclusion_of :gender, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_inclusion_of :gender, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_inclusion_of :age, :in => 0..99 | |
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %s is not included in the list" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( m f ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of available items. | |
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list"). | |
- # * <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>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of available items | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list") | |
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is null (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. | |
@@ -731,10 +739,19 @@ module ActiveRecord | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- unless enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ unless enum_object.include?(value) | |
message = record.errors.generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value) | |
record.errors.add(attr_name, message) | |
end | |
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb | |
index 5899a84..ab9cfbe 100644 | |
--- a/activerecord/test/cases/validations_test.rb | |
+++ b/activerecord/test/cases/validations_test.rb | |
@@ -652,6 +652,13 @@ class ValidationsTest < ActiveRecord::TestCase | |
assert Topic.create("title" => nil).valid? | |
assert Topic.create("title" => "abcde").valid? | |
end | |
+ | |
+ def test_validates_inclusion_of | |
+ Topic.validates_inclusion_of( :title, :in => %w( abe monkey ) ) | |
+ | |
+ assert Topic.create("title" => "monkey", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "something", "content" => "abc").valid? | |
+ end | |
def test_validates_inclusion_of_with_formatted_message | |
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %s is not in the list" ) | |
@@ -663,6 +670,37 @@ class ValidationsTest < ActiveRecord::TestCase | |
assert t.errors.on(:title) | |
assert_equal "option uhoh is not in the list", t.errors["title"] | |
end | |
+ | |
+ def test_validates_inclusion_of_with_proc_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => Proc.new { |topic| [topic.class.to_s] } ) | |
+ | |
+ assert Topic.create("title" => "Topic", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "something", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_inclusion_of_with_symbol_enumerable | |
+ Topic.class_eval "def title_inclusions; ['test']; end" | |
+ | |
+ Topic.validates_inclusion_of( :title, :in => :title_inclusions ) | |
+ | |
+ assert Topic.create("title" => "test", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "something", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_inclusion_of_should_raise_argument_error_if_in_option_is_not_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => nil ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_inclusion_of_should_raise_argument_error_if_in_option_is_a_symbol_and_is_not_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => :new_record? ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_inclusion_of_should_raise_argument_error_if_in_option_is_a_proc_and_is_not_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => Proc.new { |topic| nil } ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
def test_numericality_with_allow_nil_and_getter_method | |
Developer.validates_numericality_of( :salary, :allow_nil => true) | |
-- | |
1.5.4.3 | |
From 6e637df1fc7244d862fadd46e538fde46f8bbd24 Mon Sep 17 00:00:00 2001 | |
From: Sean Huber <[email protected]> | |
Date: Wed, 20 Aug 2008 11:54:15 -0700 | |
Subject: [PATCH] Updated ActiveRecord CHANGELOG | |
--- | |
activerecord/CHANGELOG | 2 ++ | |
1 files changed, 2 insertions(+), 0 deletions(-) | |
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG | |
index 90be9b7..6245d7e 100644 | |
--- a/activerecord/CHANGELOG | |
+++ b/activerecord/CHANGELOG | |
@@ -1,5 +1,7 @@ | |
*Edge* | |
+* validates_exclusion_of and validates_inclusion_of can now accept a symbol representing an instance method or a proc object as the :in or :within option | |
+ | |
* Set config.active_record.timestamped_migrations = false to have migrations with numeric prefix instead of UTC timestamp. #446. [Andrew Stone, Nik Wakelin] | |
* change_column_default preserves the not-null constraint. #617 [Tarmo Tänav] | |
-- | |
1.5.4.3 | |
From 9f77d913a49a13afc0f16778acd06af962272c47 Mon Sep 17 00:00:00 2001 | |
From: Sean Huber <[email protected]> | |
Date: Thu, 21 Aug 2008 10:05:48 -0700 | |
Subject: [PATCH] validates_exclusion/inclusion_of checks 'case enum' instead of 'case enum.class.to_s' | |
--- | |
.../lib/active_model/validations/exclusion.rb | 10 +++++----- | |
.../lib/active_model/validations/inclusion.rb | 10 +++++----- | |
activerecord/lib/active_record/validations.rb | 20 ++++++++++---------- | |
3 files changed, 20 insertions(+), 20 deletions(-) | |
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb | |
index 1a4dd87..380dbc3 100644 | |
--- a/activemodel/lib/active_model/validations/exclusion.rb | |
+++ b/activemodel/lib/active_model/validations/exclusion.rb | |
@@ -35,11 +35,11 @@ module ActiveModel | |
enum = configuration[:in] || configuration[:within] | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- enum_object = case enum.class.to_s | |
- when 'Symbol' | |
- then record.send(enum) | |
- when 'Proc' | |
- then enum.call(record) | |
+ enum_object = case enum | |
+ when Symbol | |
+ record.send(enum) | |
+ when Proc | |
+ enum.call(record) | |
else | |
enum | |
end | |
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb | |
index 6c1eabe..abdbd13 100644 | |
--- a/activemodel/lib/active_model/validations/inclusion.rb | |
+++ b/activemodel/lib/active_model/validations/inclusion.rb | |
@@ -35,11 +35,11 @@ module ActiveModel | |
enum = configuration[:in] || configuration[:within] | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- enum_object = case enum.class.to_s | |
- when 'Symbol' | |
- then record.send(enum) | |
- when 'Proc' | |
- then enum.call(record) | |
+ enum_object = case enum | |
+ when Symbol | |
+ record.send(enum) | |
+ when Proc | |
+ enum.call(record) | |
else | |
enum | |
end | |
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb | |
index 0a3a00e..aad1c2f 100644 | |
--- a/activerecord/lib/active_record/validations.rb | |
+++ b/activerecord/lib/active_record/validations.rb | |
@@ -740,11 +740,11 @@ module ActiveRecord | |
enum = configuration[:in] || configuration[:within] | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- enum_object = case enum.class.to_s | |
- when 'Symbol' | |
- then record.send(enum) | |
- when 'Proc' | |
- then enum.call(record) | |
+ enum_object = case enum | |
+ when Symbol | |
+ record.send(enum) | |
+ when Proc | |
+ enum.call(record) | |
else | |
enum | |
end | |
@@ -792,11 +792,11 @@ module ActiveRecord | |
enum = configuration[:in] || configuration[:within] | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- enum_object = case enum.class.to_s | |
- when 'Symbol' | |
- then record.send(enum) | |
- when 'Proc' | |
- then enum.call(record) | |
+ enum_object = case enum | |
+ when Symbol | |
+ record.send(enum) | |
+ when Proc | |
+ enum.call(record) | |
else | |
enum | |
end | |
-- | |
1.5.4.3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 382ff3faf9f300222507e3531006cfc27df2c517 Mon Sep 17 00:00:00 2001 | |
From: Sean Huber <[email protected]> | |
Date: Wed, 20 Aug 2008 11:29:55 -0700 | |
Subject: [PATCH] validates_exclusion_of can now accept a symbol representing an instance method or a proc object as the :in/:within option | |
--- | |
.../lib/active_model/validations/exclusion.rb | 25 +++++++++++++-- | |
activerecord/lib/active_record/validations.rb | 31 +++++++++++++++---- | |
activerecord/test/cases/validations_test.rb | 31 ++++++++++++++++++++ | |
3 files changed, 76 insertions(+), 11 deletions(-) | |
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb | |
index f3367ab..1a4dd87 100644 | |
--- a/activemodel/lib/active_model/validations/exclusion.rb | |
+++ b/activemodel/lib/active_model/validations/exclusion.rb | |
@@ -5,12 +5,20 @@ module ActiveModel | |
# | |
# class Person < ActiveRecord::Base | |
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here" | |
+ # validates_exclusion_of :username, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_exclusion_of :username, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60" | |
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %s is not allowed" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( admin superuser ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of | |
+ # * <tt>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of items that the value shouldn't be part of | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
# * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved") | |
# * <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+) | |
@@ -26,10 +34,19 @@ module ActiveModel | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- record.errors.add(attr_name, configuration[:message] % value) if enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ record.errors.add(attr_name, configuration[:message] % value) if enum_object.include?(value) | |
end | |
end | |
end | |
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb | |
index b7e6394..7b0d188 100644 | |
--- a/activerecord/lib/active_record/validations.rb | |
+++ b/activerecord/lib/active_record/validations.rb | |
@@ -745,15 +745,23 @@ module ActiveRecord | |
# | |
# class Person < ActiveRecord::Base | |
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here" | |
+ # validates_exclusion_of :username, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_exclusion_of :username, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60" | |
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %s is not allowed" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( admin superuser ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of. | |
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved"). | |
- # * <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>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of items that the value shouldn't be part of | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved") | |
+ # * <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. | |
@@ -766,10 +774,19 @@ module ActiveRecord | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- if enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ if enum_object.include?(value) | |
message = record.errors.generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value) | |
record.errors.add(attr_name, message) | |
end | |
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb | |
index 4b2d28c..5899a84 100644 | |
--- a/activerecord/test/cases/validations_test.rb | |
+++ b/activerecord/test/cases/validations_test.rb | |
@@ -688,6 +688,37 @@ class ValidationsTest < ActiveRecord::TestCase | |
assert t.errors.on(:title) | |
assert_equal "option monkey is restricted", t.errors["title"] | |
end | |
+ | |
+ def test_validates_exclusion_of_with_proc_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => Proc.new { |topic| [topic.class.to_s] } ) | |
+ | |
+ assert Topic.create("title" => "something", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "Topic", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_exclusion_of_with_symbol_enumerable | |
+ Topic.class_eval "def title_exclusions; ['test']; end" | |
+ | |
+ Topic.validates_exclusion_of( :title, :in => :title_exclusions ) | |
+ | |
+ assert Topic.create("title" => "something", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "test", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_exclusion_of_should_raise_argument_error_if_in_option_is_not_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => nil ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_exclusion_of_should_raise_argument_error_if_in_option_is_a_symbol_and_is_not_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => :new_record? ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_exclusion_of_should_raise_argument_error_if_in_option_is_a_proc_and_is_not_enumerable | |
+ Topic.validates_exclusion_of( :title, :in => Proc.new { |topic| nil } ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
def test_validates_length_of_using_minimum | |
Topic.validates_length_of :title, :minimum => 5 | |
-- | |
1.5.4.3 | |
From f7c7db1ba3115c1c90e62fce0105d7486c001c75 Mon Sep 17 00:00:00 2001 | |
From: Sean Huber <[email protected]> | |
Date: Wed, 20 Aug 2008 11:46:24 -0700 | |
Subject: [PATCH] validates_inclusion_of can now accept a symbol representing an instance method or a proc object as the :in/:within option | |
--- | |
.../lib/active_model/validations/inclusion.rb | 25 +++++++++++-- | |
activerecord/lib/active_record/validations.rb | 31 ++++++++++++---- | |
activerecord/test/cases/validations_test.rb | 38 ++++++++++++++++++++ | |
3 files changed, 83 insertions(+), 11 deletions(-) | |
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb | |
index 9fc1caa..6c1eabe 100644 | |
--- a/activemodel/lib/active_model/validations/inclusion.rb | |
+++ b/activemodel/lib/active_model/validations/inclusion.rb | |
@@ -5,12 +5,20 @@ module ActiveModel | |
# | |
# class Person < ActiveRecord::Base | |
# validates_inclusion_of :gender, :in => %w( m f ), :message => "woah! what are you then!??!!" | |
+ # validates_inclusion_of :gender, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_inclusion_of :gender, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_inclusion_of :age, :in => 0..99 | |
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %s is not included in the list" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( m f ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of available items | |
+ # * <tt>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of available items | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
# * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list") | |
# * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is null (default is: +false+) | |
# * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the attribute is blank (default is: +false+) | |
@@ -26,10 +34,19 @@ module ActiveModel | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- record.errors.add(attr_name, configuration[:message] % value) unless enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ record.errors.add(attr_name, configuration[:message] % value) unless enum_object.include?(value) | |
end | |
end | |
end | |
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb | |
index 7b0d188..0a3a00e 100644 | |
--- a/activerecord/lib/active_record/validations.rb | |
+++ b/activerecord/lib/active_record/validations.rb | |
@@ -710,15 +710,23 @@ module ActiveRecord | |
# | |
# class Person < ActiveRecord::Base | |
# validates_inclusion_of :gender, :in => %w( m f ), :message => "woah! what are you then!??!!" | |
+ # validates_inclusion_of :gender, :in => :some_method_that_returns_an_enumerable_object | |
+ # validates_inclusion_of :gender, :in => Proc.new { |person| person.some_method_that_returns_an_enumerable_object } | |
# validates_inclusion_of :age, :in => 0..99 | |
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %s is not included in the list" | |
+ # | |
+ # def some_method_that_returns_an_enumerable_object | |
+ # %w( m f ) | |
+ # end | |
# end | |
# | |
# Configuration options: | |
- # * <tt>:in</tt> - An enumerable object of available items. | |
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list"). | |
- # * <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>:in</tt> - An enumerable object, a symbol representing an instance method of the current class that returns | |
+ # an enumerable object, or a Proc that returns an enumerable object of available items | |
+ # * <tt>:within</tt> - A synonym (or alias) for <tt>:in</tt> | |
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list") | |
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is null (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. | |
@@ -731,10 +739,19 @@ module ActiveRecord | |
enum = configuration[:in] || configuration[:within] | |
- raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") | |
- | |
validates_each(attr_names, configuration) do |record, attr_name, value| | |
- unless enum.include?(value) | |
+ enum_object = case enum.class.to_s | |
+ when 'Symbol' | |
+ then record.send(enum) | |
+ when 'Proc' | |
+ then enum.call(record) | |
+ else | |
+ enum | |
+ end | |
+ | |
+ raise(ArgumentError, "An object with the method include? is required must be supplied as the :in or :within option of the configuration hash") unless enum_object.respond_to?("include?") | |
+ | |
+ unless enum_object.include?(value) | |
message = record.errors.generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value) | |
record.errors.add(attr_name, message) | |
end | |
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb | |
index 5899a84..ab9cfbe 100644 | |
--- a/activerecord/test/cases/validations_test.rb | |
+++ b/activerecord/test/cases/validations_test.rb | |
@@ -652,6 +652,13 @@ class ValidationsTest < ActiveRecord::TestCase | |
assert Topic.create("title" => nil).valid? | |
assert Topic.create("title" => "abcde").valid? | |
end | |
+ | |
+ def test_validates_inclusion_of | |
+ Topic.validates_inclusion_of( :title, :in => %w( abe monkey ) ) | |
+ | |
+ assert Topic.create("title" => "monkey", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "something", "content" => "abc").valid? | |
+ end | |
def test_validates_inclusion_of_with_formatted_message | |
Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %s is not in the list" ) | |
@@ -663,6 +670,37 @@ class ValidationsTest < ActiveRecord::TestCase | |
assert t.errors.on(:title) | |
assert_equal "option uhoh is not in the list", t.errors["title"] | |
end | |
+ | |
+ def test_validates_inclusion_of_with_proc_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => Proc.new { |topic| [topic.class.to_s] } ) | |
+ | |
+ assert Topic.create("title" => "Topic", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "something", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_inclusion_of_with_symbol_enumerable | |
+ Topic.class_eval "def title_inclusions; ['test']; end" | |
+ | |
+ Topic.validates_inclusion_of( :title, :in => :title_inclusions ) | |
+ | |
+ assert Topic.create("title" => "test", "content" => "abc").valid? | |
+ assert !Topic.create("title" => "something", "content" => "abc").valid? | |
+ end | |
+ | |
+ def test_validates_inclusion_of_should_raise_argument_error_if_in_option_is_not_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => nil ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_inclusion_of_should_raise_argument_error_if_in_option_is_a_symbol_and_is_not_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => :new_record? ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
+ | |
+ def test_validates_inclusion_of_should_raise_argument_error_if_in_option_is_a_proc_and_is_not_enumerable | |
+ Topic.validates_inclusion_of( :title, :in => Proc.new { |topic| nil } ) | |
+ assert_raises(ArgumentError) { Topic.create("title" => "something", "content" => "abc") } | |
+ end | |
def test_numericality_with_allow_nil_and_getter_method | |
Developer.validates_numericality_of( :salary, :allow_nil => true) | |
-- | |
1.5.4.3 | |
From 80600bc8b55a3d5ffe0a834a81f8c695265bae85 Mon Sep 17 00:00:00 2001 | |
From: Sean Huber <[email protected]> | |
Date: Wed, 20 Aug 2008 11:54:15 -0700 | |
Subject: [PATCH] Updated ActiveRecord CHANGELOG | |
--- | |
activerecord/CHANGELOG | 2 ++ | |
1 files changed, 2 insertions(+), 0 deletions(-) | |
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG | |
index 90be9b7..6245d7e 100644 | |
--- a/activerecord/CHANGELOG | |
+++ b/activerecord/CHANGELOG | |
@@ -1,5 +1,7 @@ | |
*Edge* | |
+* validates_exclusion_of and validates_inclusion_of can now accept a symbol representing an instance method or a proc object as the :in or :within option | |
+ | |
* Set config.active_record.timestamped_migrations = false to have migrations with numeric prefix instead of UTC timestamp. #446. [Andrew Stone, Nik Wakelin] | |
* change_column_default preserves the not-null constraint. #617 [Tarmo Tänav] | |
-- | |
1.5.4.3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment