Skip to content

Commit 8620bf9

Browse files
committed
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
1 parent 5912f3f commit 8620bf9

File tree

12 files changed

+75
-6
lines changed

12 files changed

+75
-6
lines changed

activemodel/lib/active_model/errors.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ module ActiveModel
6363
class Errors
6464
include Enumerable
6565

66-
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank]
66+
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
6767

6868
attr_reader :messages
6969

@@ -218,6 +218,9 @@ def add(attribute, message = nil, options = {})
218218
elsif message.is_a?(Proc)
219219
message = message.call
220220
end
221+
if options[:strict]
222+
raise ActiveModel::StrictValidationFailed, message
223+
end
221224

222225
self[attribute] << message
223226
end
@@ -319,4 +322,7 @@ def generate_message(attribute, type = :invalid, options = {})
319322
I18n.translate(key, options)
320323
end
321324
end
325+
326+
class StrictValidationFailed < StandardError
327+
end
322328
end

activemodel/lib/active_model/validations/acceptance.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ module HelperMethods
5858
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
5959
# The method, proc or string should return or evaluate to a true or
6060
# false value.
61+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
62+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
6163
def validates_acceptance_of(*attr_names)
6264
validates_with AcceptanceValidator, _merge_attributes(attr_names)
6365
end

activemodel/lib/active_model/validations/confirmation.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ module HelperMethods
5858
# <tt>:unless => :skip_validation</tt>, or
5959
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
6060
# method, proc or string should return or evaluate to a true or false value.
61+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
62+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
6163
def validates_confirmation_of(*attr_names)
6264
validates_with ConfirmationValidator, _merge_attributes(attr_names)
6365
end

activemodel/lib/active_model/validations/exclusion.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ module HelperMethods
5959
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
6060
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
6161
# method, proc or string should return or evaluate to a true or false value.
62+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
63+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
6264
def validates_exclusion_of(*attr_names)
6365
validates_with ExclusionValidator, _merge_attributes(attr_names)
6466
end

activemodel/lib/active_model/validations/format.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ module HelperMethods
8484
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
8585
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
8686
# method, proc or string should return or evaluate to a true or false value.
87+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
88+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
8789
def validates_format_of(*attr_names)
8890
validates_with FormatValidator, _merge_attributes(attr_names)
8991
end

activemodel/lib/active_model/validations/inclusion.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ module HelperMethods
5959
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
6060
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
6161
# method, proc or string should return or evaluate to a true or false value.
62+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
63+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
6264
def validates_inclusion_of(*attr_names)
6365
validates_with InclusionValidator, _merge_attributes(attr_names)
6466
end

activemodel/lib/active_model/validations/length.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ module HelperMethods
9696
# * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
9797
# count words as in above example.)
9898
# Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
99+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
100+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
99101
def validates_length_of(*attr_names)
100102
validates_with LengthValidator, _merge_attributes(attr_names)
101103
end

activemodel/lib/active_model/validations/numericality.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ module HelperMethods
107107
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
108108
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
109109
# method, proc or string should return or evaluate to a true or false value.
110+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
111+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
110112
#
111113
# The following checks can also be supplied with a proc or a symbol which corresponds to a method:
112114
# * <tt>:greater_than</tt>

activemodel/lib/active_model/validations/presence.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ module HelperMethods
3535
# * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
3636
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
3737
# The method, proc or string should return or evaluate to a true or false value.
38+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
39+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
3840
#
3941
def validates_presence_of(*attr_names)
4042
validates_with PresenceValidator, _merge_attributes(attr_names)

activemodel/lib/active_model/validations/validates.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ module ClassMethods
7070
# validator's initializer as +options[:in]+ while other types including
7171
# regular expressions and strings are passed as +options[:with]+
7272
#
73-
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+ and +:allow_nil+ can be given
74-
# to one specific validator, as a hash:
73+
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ and +:strict+
74+
# can be given to one specific validator, as a hash:
7575
#
7676
# validates :password, :presence => { :if => :password_required? }, :confirmation => true
7777
#
@@ -101,12 +101,24 @@ def validates(*attributes)
101101
end
102102
end
103103

104+
# This method is used to define validation that can not be correcterized by end user
105+
# and is considered exceptional.
106+
# So each validator defined with bang or <tt>:strict</tt> option set to <tt>true</tt>
107+
# will always raise <tt>ActiveModel::InternalValidationFailed</tt> instead of adding error
108+
# when validation fails
109+
# See <tt>validates</tt> for more information about validation itself.
110+
def validates!(*attributes)
111+
options = attributes.extract_options!
112+
options[:strict] = true
113+
validates(*(attributes << options))
114+
end
115+
104116
protected
105117

106118
# When creating custom validators, it might be useful to be able to specify
107119
# additional default keys. This can be done by overwriting this method.
108120
def _validates_default_keys
109-
[ :if, :unless, :on, :allow_blank, :allow_nil ]
121+
[ :if, :unless, :on, :allow_blank, :allow_nil , :strict]
110122
end
111123

112124
def _parse_validates_options(options) #:nodoc:

activemodel/lib/active_model/validations/with.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ module ClassMethods
6161
# (e.g. <tt>:unless => :skip_validation</tt>, or
6262
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
6363
# The method, proc or string should return or evaluate to a true or false value.
64-
#
64+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
65+
# See <tt>ActiveModel::Validation#validates!</tt> for more information
66+
6567
# If you pass any additional configuration options, they will be passed
6668
# to the class and available as <tt>options</tt>:
6769
#
@@ -140,4 +142,4 @@ def validates_with(*args, &block)
140142
end
141143
end
142144
end
143-
end
145+
end

activemodel/test/cases/validations_test.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,37 @@ def test_validations_on_the_instance_level
297297

298298
assert auto.valid?
299299
end
300+
301+
def test_strict_validation_in_validates
302+
Topic.validates :title, :strict => true, :presence => true
303+
assert_raises ActiveModel::StrictValidationFailed do
304+
Topic.new.valid?
305+
end
306+
end
307+
308+
def test_strict_validation_not_fails
309+
Topic.validates :title, :strict => true, :presence => true
310+
assert Topic.new(:title => "hello").valid?
311+
end
312+
313+
def test_strict_validation_particular_validator
314+
Topic.validates :title, :presence => {:strict => true}
315+
assert_raises ActiveModel::StrictValidationFailed do
316+
Topic.new.valid?
317+
end
318+
end
319+
320+
def test_strict_validation_in_custom_validator_helper
321+
Topic.validates_presence_of :title, :strict => true
322+
assert_raises ActiveModel::StrictValidationFailed do
323+
Topic.new.valid?
324+
end
325+
end
326+
327+
def test_validates_with_bang
328+
Topic.validates! :title, :presence => true
329+
assert_raises ActiveModel::StrictValidationFailed do
330+
Topic.new.valid?
331+
end
332+
end
300333
end

0 commit comments

Comments
 (0)