Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
moving before_validation and after_validation functionality from Acti…
…veRecord to ActiveModel [#4653 state:resolved] Signed-off-by: José Valim <jose.valim@gmail.com>
- Loading branch information
Showing
6 changed files
with
148 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
require 'active_support/callbacks' | ||
|
||
module ActiveModel | ||
module Validations | ||
module Callbacks | ||
# == Active Model Validation callbacks | ||
# | ||
# Provides an interface for any class to have <tt>before_validation</tt> and | ||
# <tt>after_validation</tt> callbacks. | ||
# | ||
# First, extend ActiveModel::Callbacks from the class you are creating: | ||
# | ||
# class MyModel | ||
# include ActiveModel::Validations::Callbacks | ||
# | ||
# before_validation :do_stuff_before_validation | ||
# after_validation :do_tuff_after_validation | ||
# end | ||
# | ||
# Like other before_* callbacks if <tt>before_validation</tt> returns false | ||
# then <tt>valid?</tt> will not be called. | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
include ActiveSupport::Callbacks | ||
define_callbacks :validation, :terminator => "result == false", :scope => [:kind, :name] | ||
end | ||
|
||
module ClassMethods | ||
def before_validation(*args, &block) | ||
options = args.last | ||
if options.is_a?(Hash) && options[:on] | ||
options[:if] = Array.wrap(options[:if]) | ||
options[:if] << "self.validation_context == :#{options[:on]}" | ||
end | ||
set_callback(:validation, :before, *args, &block) | ||
end | ||
|
||
def after_validation(*args, &block) | ||
options = args.extract_options! | ||
options[:prepend] = true | ||
options[:if] = Array.wrap(options[:if]) | ||
options[:if] << "!halted && value != false" | ||
options[:if] << "self.validation_context == :#{options[:on]}" if options[:on] | ||
set_callback(:validation, :after, *(args << options), &block) | ||
end | ||
end | ||
|
||
# Runs all the specified validations and returns true if no errors were added | ||
# otherwise false. Context can optionally be supplied to define which callbacks | ||
# to test against (the context is defined on the validations using :on). | ||
def valid?(context = nil) | ||
current_context, self.validation_context = validation_context, context | ||
errors.clear | ||
@validate_callback_result = nil | ||
validation_callback_result = _run_validation_callbacks { @validate_callback_result = _run_validate_callbacks } | ||
(validation_callback_result && @validate_callback_result) ? errors.empty? : false | ||
ensure | ||
self.validation_context = current_context | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# encoding: utf-8 | ||
require 'cases/helper' | ||
|
||
class Dog | ||
include ActiveModel::Validations | ||
|
||
attr_accessor :name, :history | ||
|
||
def history | ||
@history ||= [] | ||
end | ||
end | ||
|
||
class DogWithMethodCallbacks < Dog | ||
before_validation :set_before_validation_marker | ||
after_validation :set_after_validation_marker | ||
|
||
def set_before_validation_marker; self.history << 'before_validation_marker'; end | ||
def set_after_validation_marker; self.history << 'after_validation_marker' ; end | ||
end | ||
|
||
class DogValidtorsAreProc < Dog | ||
before_validation { self.history << 'before_validation_marker' } | ||
after_validation { self.history << 'after_validation_marker' } | ||
end | ||
|
||
class DogWithTwoValidators < Dog | ||
before_validation { self.history << 'before_validation_marker1' } | ||
before_validation { self.history << 'before_validation_marker2' } | ||
end | ||
|
||
class DogValidatorReturningFalse < Dog | ||
before_validation { false } | ||
before_validation { self.history << 'before_validation_marker2' } | ||
end | ||
|
||
class DogWithMissingName < Dog | ||
before_validation { self.history << 'before_validation_marker' } | ||
validates_presence_of :name | ||
end | ||
|
||
class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase | ||
|
||
def test_before_validation_and_after_validation_callbacks_should_be_called | ||
d = DogWithMethodCallbacks.new | ||
d.valid? | ||
assert_equal ['before_validation_marker', 'after_validation_marker'], d.history | ||
end | ||
|
||
def test_before_validation_and_after_validation_callbacks_should_be_called_with_proc | ||
d = DogValidtorsAreProc.new | ||
d.valid? | ||
assert_equal ['before_validation_marker', 'after_validation_marker'], d.history | ||
end | ||
|
||
def test_before_validation_and_after_validation_callbacks_should_be_called_in_declared_order | ||
d = DogWithTwoValidators.new | ||
d.valid? | ||
assert_equal ['before_validation_marker1', 'before_validation_marker2'], d.history | ||
end | ||
|
||
def test_further_callbacks_should_not_be_called_if_before_validation_returns_false | ||
d = DogValidatorReturningFalse.new | ||
output = d.valid? | ||
assert_equal [], d.history | ||
assert_equal false, output | ||
end | ||
|
||
def test_validation_test_should_be_done | ||
d = DogWithMissingName.new | ||
output = d.valid? | ||
assert_equal ['before_validation_marker'], d.history | ||
assert_equal false, output | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters