From 5b983f6f6b92846a0f96757b0dc9e99e3d980df0 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 9 Dec 2004 15:06:24 +0000 Subject: [PATCH] Fixed Base.errors to be indifferent as to whether strings or symbols are used. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@98 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/CHANGELOG | 12 +++++++ activerecord/lib/active_record/validations.rb | 35 +++++++++++-------- activerecord/test/validations_test.rb | 15 ++++++++ 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 6299d386f41..3a8c81453a6 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,17 @@ *CVS* +* Fixed Base.errors to be indifferent as to whether strings or symbols are used. Examples: + + Before: + errors.add(:name, "must be shorter") if name.size > 10 + errors.on(:name) # => "must be shorter" + errors.on("name") # => nil + + After: + errors.add(:name, "must be shorter") if name.size > 10 + errors.on(:name) # => "must be shorter" + errors.on("name") # => "must be shorter" + * Added Base.validate_confirmation that encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example: Model: diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 71cbb5a6e5a..1c2680e639c 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -60,7 +60,8 @@ module ActiveRecord # # Model: # class Person < ActiveRecord::Base - # validate_confirmation :password + # validate_confirmation :user_name, :password + # validate_confirmation :email_address, "should match confirmation" # end # # View: @@ -73,20 +74,22 @@ module ActiveRecord # NOTE: This validation is only happening on create. When you want to update the record, you'll have to decide and pursue your # own course of action. def validate_confirmation(*attr_names) + error_message = attr_names.last.is_a?(String) ? attr_names.pop : "doesn't match confirmation" + for attr_name in attr_names attr_accessor "#{attr_name}_confirmation" class_eval <<-EOM - validate_on_create %{errors.add('#{attr_name}', "doesn't match confirmation") unless #{attr_name} == #{attr_name}_confirmation} + validate_on_create %{errors.add('#{attr_name}', "#{error_message}") unless #{attr_name} == #{attr_name}_confirmation} EOM end end - # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example: # # Model: # class Person < ActiveRecord::Base # validate_acceptance :terms_of_service + # validate_acceptance :eula, "must be abided" # end # # View: @@ -96,10 +99,12 @@ EOM # # NOTE: The agreement is considered valid if it's set to the string "1". This makes it easy to relate it to an HTML checkbox. def validate_acceptance(*attr_names) + error_message = attr_names.last.is_a?(String) ? attr_names.pop : "must be accepted" + for attr_name in attr_names attr_accessor(attr_name) class_eval <<-EOM - validate_on_create %{errors.add('#{attr_name}', "must be accepted") unless #{attr_name} == "1"} + validate_on_create %{errors.add('#{attr_name}', '#{error_message}') unless #{attr_name} == "1"} EOM end end @@ -208,21 +213,21 @@ EOM # error can be added to the same +attribute+ in which case an array will be returned on a call to on(attribute). # If no +msg+ is supplied, "invalid" is assumed. def add(attribute, msg = "invalid") - @errors[attribute] = [] if @errors[attribute].nil? - @errors[attribute] << msg + @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil? + @errors[attribute.to_s] << msg end # Will add an error message to each of the attributes in +attributes+ that is empty (defined by attribute_present?). def add_on_empty(attributes, msg = "can't be empty") - [attributes].flatten.each { |attr| add(attr, msg) unless @base.attribute_present?(attr) } + [attributes].flatten.each { |attr| add(attr, msg) unless @base.attribute_present?(attr.to_s) } end # Will add an error message to each of the attributes in +attributes+ that has a length outside of the passed boundary +range+. # If the length is above the boundary, the too_long_msg message will be used. If below, the too_short_msg. def add_on_boundary_breaking(attributes, range, too_long_msg = "is too long (max is %d characters)", too_short_msg = "is too short (min is %d characters)") for attr in [attributes].flatten - add(attr, too_short_msg % range.begin) if @base.attribute_present?(attr) && @base.send(attr).length < range.begin - add(attr, too_long_msg % range.end) if @base.attribute_present?(attr) && @base.send(attr).length > range.end + add(attr, too_short_msg % range.begin) if @base.attribute_present?(attr.to_s) && @base.send(attr.to_s).length < range.begin + add(attr, too_long_msg % range.end) if @base.attribute_present?(attr.to_s) && @base.send(attr.to_s).length > range.end end end @@ -230,19 +235,19 @@ EOM # Returns true if the specified +attribute+ has errors associated with it. def invalid?(attribute) - !@errors[attribute].nil? + !@errors[attribute.to_s].nil? end # * Returns nil, if no errors are associated with the specified +attribute+. # * Returns the error message, if one error is associated with the specified +attribute+. # * Returns an array of error messages, if more than one error is associated with the specified +attribute+. def on(attribute) - if @errors[attribute].nil? + if @errors[attribute.to_s].nil? nil - elsif @errors[attribute].length == 1 - @errors[attribute].first + elsif @errors[attribute.to_s].length == 1 + @errors[attribute.to_s].first else - @errors[attribute] + @errors[attribute.to_s] end end @@ -270,7 +275,7 @@ EOM @errors.each_key do |attr| @errors[attr].each do |msg| - if attr == :base + if attr == "base" full_messages << msg else full_messages << @base.class.human_attribute_name(attr) + " " + msg diff --git a/activerecord/test/validations_test.rb b/activerecord/test/validations_test.rb index c396d30630a..8e25453faef 100755 --- a/activerecord/test/validations_test.rb +++ b/activerecord/test/validations_test.rb @@ -138,10 +138,25 @@ class ValidationsTest < Test::Unit::TestCase t = Topic.create("title" => "We should be confirmed") assert !t.save + assert_equal "must be accepted", t.errors.on(:terms_of_service) t.terms_of_service = "1" assert t.save Topic.write_inheritable_attribute("validate_on_create", []) end + + + def test_eula + Topic.validate_acceptance(:eula, "must be abided") + + t = Topic.create("title" => "We should be confirmed") + assert !t.save + assert_equal "must be abided", t.errors.on(:eula) + + t.eula = "1" + assert t.save + + Topic.write_inheritable_attribute("validate_on_create", []) + end end \ No newline at end of file