From 2e4f7986b8ec90d7b41c385388be21b8cee79b9c Mon Sep 17 00:00:00 2001 From: Bogdan Gusiev Date: Mon, 6 Aug 2012 13:45:27 +0300 Subject: [PATCH] AM::Validation#validates: ability to pass custom exception to `:strict` option --- activemodel/CHANGELOG.md | 2 ++ activemodel/lib/active_model/errors.rb | 8 ++++++-- activemodel/lib/active_model/validations/validates.rb | 7 +++++-- activemodel/test/cases/validations_test.rb | 9 +++++++++ .../source/active_record_validations_callbacks.textile | 10 ++++++++++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 847ae7f237..b9966cb2fa 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,5 +1,7 @@ ## 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. Now, AM Serializers and AR objects have the same default behaviour. Fixes #6578. diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 1026b0f4d3..b3b9ba8e56 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -283,15 +283,19 @@ module ActiveModel # # If the :strict option is set to true will raise # ActiveModel::StrictValidationFailed instead of adding the error. + # :strict option can also be set to any other exception. # # person.errors.add(:name, nil, strict: true) # # => ActiveModel::StrictValidationFailed: name is invalid + # person.errors.add(:name, nil, strict: NameIsInvalid) + # # => NameIsInvalid: name is invalid # # person.errors.messages # => {} def add(attribute, message = nil, options = {}) message = normalize_message(attribute, message, options) - if options[:strict] - raise ActiveModel::StrictValidationFailed, full_message(attribute, message) + if exception = options[:strict] + exception = ActiveModel::StrictValidationFailed if exception == true + raise exception, full_message(attribute, message) end self[attribute] << message diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index 5892ad29d1..eb6e604851 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -84,12 +84,15 @@ module ActiveModel # or unless: Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a +true+ or # +false+ value. - # * :strict - Specifies whether validation should be strict. - # See ActiveModel::Validation#validates! for more information. + # * :strict - if the :strict option is set to true + # will raise ActiveModel::StrictValidationFailed instead of adding the error. + # :strict option can also be set to any other exception. # # Example: # # 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+ # and +:strict+ can be given to one specific validator, as a hash: diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 8ea9745fbf..a9d32808da 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -11,6 +11,8 @@ require 'active_support/xml_mini' class ValidationsTest < ActiveModel::TestCase + class CustomStrictValidationException < StandardError; end + def setup Topic._validators.clear end @@ -323,6 +325,13 @@ class ValidationsTest < ActiveModel::TestCase 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 Topic.validates! :title, :presence => true assert_raises ActiveModel::StrictValidationFailed do diff --git a/guides/source/active_record_validations_callbacks.textile b/guides/source/active_record_validations_callbacks.textile index cf7293bd9e..b866337e3f 100644 --- a/guides/source/active_record_validations_callbacks.textile +++ b/guides/source/active_record_validations_callbacks.textile @@ -532,6 +532,16 @@ end Person.new.valid? => ActiveModel::StrictValidationFailed: Name can't be blank +There is also an ability to pass custom exception to +:strict+ option + + +class Person < ActiveRecord::Base + validates :token, :presence => true, :uniqueness => true, :strict => TokenGenerationException +end + +Person.new.valid? => TokenGenerationException: Token can't be blank + + 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.