mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Fix validation callbacks on multiple context
I found a bug that validation callbacks don't fire on multiple context. So I've fixed it. Example: ```ruby class Dog include ActiveModel::Validations include ActiveModel::Validations::Callbacks attr_accessor :history def initialize @history = [] end before_validation :set_before_validation_on_a, on: :a before_validation :set_before_validation_on_b, on: :b after_validation :set_after_validation_on_a, on: :a after_validation :set_after_validation_on_b, on: :b def set_before_validation_on_a; history << "before_validation on a"; end def set_before_validation_on_b; history << "before_validation on b"; end def set_after_validation_on_a; history << "after_validation on a" ; end def set_after_validation_on_b; history << "after_validation on b" ; end end ``` Before: ``` d = Dog.new d.valid?([:a, :b]) d.history # [] ``` After: ``` d = Dog.new d.valid?([:a, :b]) d.history # ["before_validation on a", "before_validation on b", "after_validation on a", "after_validation on b"] ```
This commit is contained in:
parent
011f76e57b
commit
470d0e459f
3 changed files with 60 additions and 9 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
* Fix to working before/after validation callbacks on multiple contexts.
|
||||||
|
|
||||||
|
*Yoshiyuki Hirano*
|
||||||
|
|
||||||
## Rails 5.2.0.beta2 (November 28, 2017) ##
|
## Rails 5.2.0.beta2 (November 28, 2017) ##
|
||||||
|
|
||||||
* No changes.
|
* No changes.
|
||||||
|
|
|
@ -54,14 +54,16 @@ module ActiveModel
|
||||||
# person.valid? # => true
|
# person.valid? # => true
|
||||||
# person.name # => "bob"
|
# person.name # => "bob"
|
||||||
def before_validation(*args, &block)
|
def before_validation(*args, &block)
|
||||||
options = args.last
|
options = args.extract_options!
|
||||||
if options.is_a?(Hash) && options[:on]
|
|
||||||
options[:if] = Array(options[:if])
|
options[:if] = Array(options[:if])
|
||||||
options[:on] = Array(options[:on])
|
|
||||||
|
if options.key?(:on)
|
||||||
options[:if].unshift ->(o) {
|
options[:if].unshift ->(o) {
|
||||||
options[:on].include? o.validation_context
|
!(Array(options[:on]) & Array(o.validation_context)).empty?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
args << options
|
||||||
set_callback(:validation, :before, *args, &block)
|
set_callback(:validation, :before, *args, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -95,13 +97,15 @@ module ActiveModel
|
||||||
options = args.extract_options!
|
options = args.extract_options!
|
||||||
options[:prepend] = true
|
options[:prepend] = true
|
||||||
options[:if] = Array(options[:if])
|
options[:if] = Array(options[:if])
|
||||||
if options[:on]
|
|
||||||
options[:on] = Array(options[:on])
|
if options.key?(:on)
|
||||||
options[:if].unshift ->(o) {
|
options[:if].unshift ->(o) {
|
||||||
options[:on].include? o.validation_context
|
!(Array(options[:on]) & Array(o.validation_context)).empty?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
set_callback(:validation, :after, *(args << options), &block)
|
|
||||||
|
args << options
|
||||||
|
set_callback(:validation, :after, *args, &block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,18 @@ class DogValidatorWithOnCondition < Dog
|
||||||
def set_after_validation_marker; history << "after_validation_marker" ; end
|
def set_after_validation_marker; history << "after_validation_marker" ; end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class DogValidatorWithOnMultipleCondition < Dog
|
||||||
|
before_validation :set_before_validation_marker_on_context_a, on: :context_a
|
||||||
|
before_validation :set_before_validation_marker_on_context_b, on: :context_b
|
||||||
|
after_validation :set_after_validation_marker_on_context_a, on: :context_a
|
||||||
|
after_validation :set_after_validation_marker_on_context_b, on: :context_b
|
||||||
|
|
||||||
|
def set_before_validation_marker_on_context_a; history << "before_validation_marker on context_a"; end
|
||||||
|
def set_before_validation_marker_on_context_b; history << "before_validation_marker on context_b"; end
|
||||||
|
def set_after_validation_marker_on_context_a; history << "after_validation_marker on context_a" ; end
|
||||||
|
def set_after_validation_marker_on_context_b; history << "after_validation_marker on context_b" ; end
|
||||||
|
end
|
||||||
|
|
||||||
class DogValidatorWithIfCondition < Dog
|
class DogValidatorWithIfCondition < Dog
|
||||||
before_validation :set_before_validation_marker1, if: -> { true }
|
before_validation :set_before_validation_marker1, if: -> { true }
|
||||||
before_validation :set_before_validation_marker2, if: -> { false }
|
before_validation :set_before_validation_marker2, if: -> { false }
|
||||||
|
@ -98,6 +110,37 @@ class CallbacksWithMethodNamesShouldBeCalled < ActiveModel::TestCase
|
||||||
assert_equal [], d.history
|
assert_equal [], d.history
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_on_multiple_condition_is_respected_for_validation_with_matching_context
|
||||||
|
d = DogValidatorWithOnMultipleCondition.new
|
||||||
|
d.valid?(:context_a)
|
||||||
|
assert_equal ["before_validation_marker on context_a", "after_validation_marker on context_a"], d.history
|
||||||
|
|
||||||
|
d = DogValidatorWithOnMultipleCondition.new
|
||||||
|
d.valid?(:context_b)
|
||||||
|
assert_equal ["before_validation_marker on context_b", "after_validation_marker on context_b"], d.history
|
||||||
|
|
||||||
|
d = DogValidatorWithOnMultipleCondition.new
|
||||||
|
d.valid?([:context_a, :context_b])
|
||||||
|
assert_equal([
|
||||||
|
"before_validation_marker on context_a",
|
||||||
|
"before_validation_marker on context_b",
|
||||||
|
"after_validation_marker on context_a",
|
||||||
|
"after_validation_marker on context_b"
|
||||||
|
], d.history)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_on_multiple_condition_is_respected_for_validation_without_matching_context
|
||||||
|
d = DogValidatorWithOnMultipleCondition.new
|
||||||
|
d.valid?(:save)
|
||||||
|
assert_equal [], d.history
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_on_multiple_condition_is_respected_for_validation_without_context
|
||||||
|
d = DogValidatorWithOnMultipleCondition.new
|
||||||
|
d.valid?
|
||||||
|
assert_equal [], d.history
|
||||||
|
end
|
||||||
|
|
||||||
def test_before_validation_and_after_validation_callbacks_should_be_called
|
def test_before_validation_and_after_validation_callbacks_should_be_called
|
||||||
d = DogWithMethodCallbacks.new
|
d = DogWithMethodCallbacks.new
|
||||||
d.valid?
|
d.valid?
|
||||||
|
|
Loading…
Reference in a new issue