Skip to content

Commit

Permalink
Implemented strict validation concept
Browse files Browse the repository at this point in the history
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 8620bf9
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 6 deletions.
8 changes: 7 additions & 1 deletion activemodel/lib/active_model/errors.rb
Expand Up @@ -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

Expand Down Expand Up @@ -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.

Copy link
@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.

Copy link
@bogdan

bogdan Feb 1, 2012

Author Contributor

Ok, I'll take a look

This comment has been minimized.

Copy link
@carlosantoniodasilva

carlosantoniodasilva Feb 1, 2012

Member

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

end

self[attribute] << message
end
Expand Down Expand Up @@ -319,4 +322,7 @@ def generate_message(attribute, type = :invalid, options = {})
I18n.translate(key, options)
end
end

class StrictValidationFailed < StandardError
end
end
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/acceptance.rb
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/confirmation.rb
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/exclusion.rb
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/format.rb
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/inclusion.rb
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/length.rb
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/numericality.rb
Expand Up @@ -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>
Expand Down
2 changes: 2 additions & 0 deletions activemodel/lib/active_model/validations/presence.rb
Expand Up @@ -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)
Expand Down
18 changes: 15 additions & 3 deletions activemodel/lib/active_model/validations/validates.rb
Expand Up @@ -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
#
Expand Down Expand Up @@ -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.

Copy link
@carlosantoniodasilva

carlosantoniodasilva Sep 12, 2011

Member

Shouldn't this be ActiveModel::StrictValidationFailed?

This comment has been minimized.

Copy link
@bogdan

bogdan Sep 13, 2011

Author 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:
Expand Down
6 changes: 4 additions & 2 deletions activemodel/lib/active_model/validations/with.rb
Expand Up @@ -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>:
#
Expand Down Expand Up @@ -140,4 +142,4 @@ def validates_with(*args, &block)
end
end
end
end
end
33 changes: 33 additions & 0 deletions activemodel/test/cases/validations_test.rb
Expand Up @@ -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.