Permalink
Browse files

Implemented strict validation concept

In order to deliver debug information to dev team
instead of display error message to end user
Implemented strict validation concept
that suppose to define validation that always raise exception when fails
  • Loading branch information...
bogdan committed Aug 17, 2011
1 parent 5912f3f commit 8620bf90c5e486e1ec44b9aabb63f8c848668ed2
@@ -63,7 +63,7 @@ module ActiveModel
class Errors
include Enumerable
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank]
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
attr_reader :messages
@@ -218,6 +218,9 @@ def add(attribute, message = nil, options = {})
elsif message.is_a?(Proc)
message = message.call
end
if options[:strict]
raise ActiveModel::StrictValidationFailed, message

This comment has been minimized.

@josevalim

josevalim Feb 1, 2012

Contributor

The message is not enough here. We also need the attribute name, otherwise we get stuff like:

 ActiveModel::StrictValidationFailed:
   can't be blank

With no mention at all of the attribute that failed.

This comment has been minimized.

@bogdan

bogdan Feb 1, 2012

Contributor

Ok, I'll take a look

This comment has been minimized.

@carlosantoniodasilva

carlosantoniodasilva Feb 1, 2012

Member

Hey mate, sorry I've just sent a PR to tackle this :).

end
self[attribute] << message
end
@@ -319,4 +322,7 @@ def generate_message(attribute, type = :invalid, options = {})
I18n.translate(key, options)
end
end
class StrictValidationFailed < StandardError
end
end
@@ -58,6 +58,8 @@ module HelperMethods
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
# The method, proc or string should return or evaluate to a true or
# false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
def validates_acceptance_of(*attr_names)
validates_with AcceptanceValidator, _merge_attributes(attr_names)
end
@@ -58,6 +58,8 @@ module HelperMethods
# <tt>:unless => :skip_validation</tt>, or
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
def validates_confirmation_of(*attr_names)
validates_with ConfirmationValidator, _merge_attributes(attr_names)
end
@@ -59,6 +59,8 @@ module HelperMethods
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
def validates_exclusion_of(*attr_names)
validates_with ExclusionValidator, _merge_attributes(attr_names)
end
@@ -84,6 +84,8 @@ module HelperMethods
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
def validates_format_of(*attr_names)
validates_with FormatValidator, _merge_attributes(attr_names)
end
@@ -59,6 +59,8 @@ module HelperMethods
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
def validates_inclusion_of(*attr_names)
validates_with InclusionValidator, _merge_attributes(attr_names)
end
@@ -96,6 +96,8 @@ module HelperMethods
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
# count words as in above example.)
# Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
def validates_length_of(*attr_names)
validates_with LengthValidator, _merge_attributes(attr_names)
end
@@ -107,6 +107,8 @@ module HelperMethods
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
#
# The following checks can also be supplied with a proc or a symbol which corresponds to a method:
# * <tt>:greater_than</tt>
@@ -35,6 +35,8 @@ module HelperMethods
# * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
# The method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
#
def validates_presence_of(*attr_names)
validates_with PresenceValidator, _merge_attributes(attr_names)
@@ -70,8 +70,8 @@ module ClassMethods
# validator's initializer as +options[:in]+ while other types including
# regular expressions and strings are passed as +options[:with]+
#
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+ and +:allow_nil+ can be given
# to one specific validator, as a hash:
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ and +:strict+
# can be given to one specific validator, as a hash:
#
# validates :password, :presence => { :if => :password_required? }, :confirmation => true
#
@@ -101,12 +101,24 @@ def validates(*attributes)
end
end
# This method is used to define validation that can not be correcterized by end user
# and is considered exceptional.
# So each validator defined with bang or <tt>:strict</tt> option set to <tt>true</tt>
# will always raise <tt>ActiveModel::InternalValidationFailed</tt> instead of adding error

This comment has been minimized.

@carlosantoniodasilva

carlosantoniodasilva Sep 12, 2011

Member

Shouldn't this be ActiveModel::StrictValidationFailed?

This comment has been minimized.

@bogdan

bogdan Sep 13, 2011

Contributor

Yes, Internal was original name. Didn't rename it here.

# when validation fails
# See <tt>validates</tt> for more information about validation itself.
def validates!(*attributes)
options = attributes.extract_options!
options[:strict] = true
validates(*(attributes << options))
end
protected
# When creating custom validators, it might be useful to be able to specify
# additional default keys. This can be done by overwriting this method.
def _validates_default_keys
[ :if, :unless, :on, :allow_blank, :allow_nil ]
[ :if, :unless, :on, :allow_blank, :allow_nil , :strict]
end
def _parse_validates_options(options) #:nodoc:
@@ -61,7 +61,9 @@ module ClassMethods
# (e.g. <tt>:unless => :skip_validation</tt>, or
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
# The method, proc or string should return or evaluate to a true or false value.
#
# * <tt>:strict</tt> - Specifies whether validation should be strict.
# See <tt>ActiveModel::Validation#validates!</tt> for more information
# If you pass any additional configuration options, they will be passed
# to the class and available as <tt>options</tt>:
#
@@ -140,4 +142,4 @@ def validates_with(*args, &block)
end
end
end
end
end
@@ -297,4 +297,37 @@ def test_validations_on_the_instance_level
assert auto.valid?
end
def test_strict_validation_in_validates
Topic.validates :title, :strict => true, :presence => true
assert_raises ActiveModel::StrictValidationFailed do
Topic.new.valid?
end
end
def test_strict_validation_not_fails
Topic.validates :title, :strict => true, :presence => true
assert Topic.new(:title => "hello").valid?
end
def test_strict_validation_particular_validator
Topic.validates :title, :presence => {:strict => true}
assert_raises ActiveModel::StrictValidationFailed do
Topic.new.valid?
end
end
def test_strict_validation_in_custom_validator_helper
Topic.validates_presence_of :title, :strict => true
assert_raises ActiveModel::StrictValidationFailed do
Topic.new.valid?
end
end
def test_validates_with_bang
Topic.validates! :title, :presence => true
assert_raises ActiveModel::StrictValidationFailed do
Topic.new.valid?
end
end
end

0 comments on commit 8620bf9

Please sign in to comment.