Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AM::Validation#validates: custom exception for :strict option #7024

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions 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.

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
# 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)
# # => 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
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
# 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.
# * <tt>:strict</tt> - if the <tt>:strict</tt> option is set to true
# will raise ActiveModel::StrictValidationFailed instead of adding the error.
# <tt>:strict</tt> 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:
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 CustomStrictValidationException < StandardError; end

def setup
Topic._validators.clear
end
Expand Down Expand Up @@ -323,6 +325,13 @@ def test_strict_validation_in_custom_validator_helper
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
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
</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

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