Skip to content

Commit

Permalink
AM::Validation#validates: ability to pass custom exception to `:stric…
Browse files Browse the repository at this point in the history
…t` option
  • Loading branch information
bogdan committed Aug 6, 2012
1 parent 5edfc46 commit 2e4f798
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 4 deletions.
2 changes: 2 additions & 0 deletions activemodel/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ## ## Rails 4.0.0 (unreleased) ##


* `AM::Validation#validates` ability to pass custom exception to `:strict` option *Bogdan Gusiev*

* Changed `AM::Serializers::JSON.include_root_in_json' default value to false. * Changed `AM::Serializers::JSON.include_root_in_json' default value to false.
Now, AM Serializers and AR objects have the same default behaviour. Fixes #6578. Now, AM Serializers and AR objects have the same default behaviour. Fixes #6578.


Expand Down
8 changes: 6 additions & 2 deletions activemodel/lib/active_model/errors.rb
Expand Up @@ -283,15 +283,19 @@ def to_hash(full_messages = false)
# #
# If the <tt>:strict</tt> option is set to true will raise # If the <tt>:strict</tt> option is set to true will raise
# ActiveModel::StrictValidationFailed instead of adding the error. # ActiveModel::StrictValidationFailed instead of adding the error.
# <tt>:strict</tt> option can also be set to any other exception.
# #
# person.errors.add(:name, nil, strict: true) # person.errors.add(:name, nil, strict: true)
# # => ActiveModel::StrictValidationFailed: name is invalid # # => ActiveModel::StrictValidationFailed: name is invalid
# person.errors.add(:name, nil, strict: NameIsInvalid)
# # => NameIsInvalid: name is invalid
# #
# person.errors.messages # => {} # person.errors.messages # => {}
def add(attribute, message = nil, options = {}) def add(attribute, message = nil, options = {})
message = normalize_message(attribute, message, options) message = normalize_message(attribute, message, options)
if options[:strict] if exception = options[:strict]
raise ActiveModel::StrictValidationFailed, full_message(attribute, message) exception = ActiveModel::StrictValidationFailed if exception == true
raise exception, full_message(attribute, message)
end end


self[attribute] << message self[attribute] << message
Expand Down
7 changes: 5 additions & 2 deletions activemodel/lib/active_model/validations/validates.rb
Expand Up @@ -84,12 +84,15 @@ module ClassMethods
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a +true+ or # method, proc or string should return or evaluate to a +true+ or
# +false+ value. # +false+ value.
# * <tt>:strict</tt> - Specifies whether validation should be strict. # * <tt>:strict</tt> - if the <tt>:strict</tt> option is set to true
# See <tt>ActiveModel::Validation#validates!</tt> for more information. # will raise ActiveModel::StrictValidationFailed instead of adding the error.
# <tt>:strict</tt> option can also be set to any other exception.
# #
# Example: # Example:
# #
# validates :password, presence: true, confirmation: true, if: :password_required? # validates :password, presence: true, confirmation: true, if: :password_required?
# validates :token, uniqueness: true, strict: TokenGenerationException
#
# #
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+ # Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+
# and +:strict+ can be given to one specific validator, as a hash: # and +:strict+ can be given to one specific validator, as a hash:
Expand Down
9 changes: 9 additions & 0 deletions activemodel/test/cases/validations_test.rb
Expand Up @@ -11,6 +11,8 @@


class ValidationsTest < ActiveModel::TestCase class ValidationsTest < ActiveModel::TestCase


class CustomStrictValidationException < StandardError; end

def setup def setup
Topic._validators.clear Topic._validators.clear
end end
Expand Down Expand Up @@ -323,6 +325,13 @@ def test_strict_validation_in_custom_validator_helper
end end
end end


def test_strict_validation_custom_exception
Topic.validates_presence_of :title, :strict => CustomStrictValidationException
assert_raises CustomStrictValidationException do
Topic.new.valid?
end
end

def test_validates_with_bang def test_validates_with_bang
Topic.validates! :title, :presence => true Topic.validates! :title, :presence => true
assert_raises ActiveModel::StrictValidationFailed do assert_raises ActiveModel::StrictValidationFailed do
Expand Down
10 changes: 10 additions & 0 deletions guides/source/active_record_validations_callbacks.textile
Expand Up @@ -532,6 +532,16 @@ end
Person.new.valid? => ActiveModel::StrictValidationFailed: Name can't be blank Person.new.valid? => ActiveModel::StrictValidationFailed: Name can't be blank
</ruby> </ruby>


There is also an ability to pass custom exception to +:strict+ option

<ruby>
class Person < ActiveRecord::Base
validates :token, :presence => true, :uniqueness => true, :strict => TokenGenerationException
end

Person.new.valid? => TokenGenerationException: Token can't be blank
</ruby>

h3. Conditional Validation h3. Conditional Validation


Sometimes it will make sense to validate an object just when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string, a +Proc+ or an +Array+. You may use the +:if+ option when you want to specify when the validation *should* happen. If you want to specify when the validation *should not* happen, then you may use the +:unless+ option. Sometimes it will make sense to validate an object just when a given predicate is satisfied. You can do that by using the +:if+ and +:unless+ options, which can take a symbol, a string, a +Proc+ or an +Array+. You may use the +:if+ option when you want to specify when the validation *should* happen. If you want to specify when the validation *should not* happen, then you may use the +:unless+ option.
Expand Down

0 comments on commit 2e4f798

Please sign in to comment.