1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #6936 from jfoley/callbacks

Fix collisions with before and after validation callbacks.
This commit is contained in:
Santiago Pastorino 2012-09-24 07:52:50 -07:00
commit 1dbe4baef5
4 changed files with 78 additions and 2 deletions

View file

@ -56,7 +56,8 @@ module ActiveModel
options = args.last
if options.is_a?(Hash) && options[:on]
options[:if] = Array(options[:if])
options[:if].unshift("self.validation_context == :#{options[:on]}")
options[:on] = Array(options[:on])
options[:if].unshift("#{options[:on]}.include? self.validation_context")
end
set_callback(:validation, :before, *args, &block)
end
@ -92,7 +93,10 @@ module ActiveModel
options = args.extract_options!
options[:prepend] = true
options[:if] = Array(options[:if])
options[:if].unshift("self.validation_context == :#{options[:on]}") if options[:on]
if options[:on]
options[:on] = Array(options[:on])
options[:if].unshift("#{options[:on]}.include? self.validation_context")
end
set_callback(:validation, :after, *(args << options), &block)
end
end

View file

@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ##
* Allow before and after validations to take an array of lifecycle events
*John Foley*
* Support for specifying transaction isolation level
If your database supports setting the isolation level for a transaction, you can set

View file

@ -137,6 +137,32 @@ class OnCallbacksDeveloper < ActiveRecord::Base
end
end
class ContextualCallbacksDeveloper < ActiveRecord::Base
self.table_name = 'developers'
before_validation { history << :before_validation }
before_validation :before_validation_on_create_and_update, :on => [ :create, :update ]
validate do
history << :validate
end
after_validation { history << :after_validation }
after_validation :after_validation_on_create_and_update, :on => [ :create, :update ]
def before_validation_on_create_and_update
history << "before_validation_on_#{self.validation_context}".to_sym
end
def after_validation_on_create_and_update
history << "after_validation_on_#{self.validation_context}".to_sym
end
def history
@history ||= []
end
end
class CallbackCancellationDeveloper < ActiveRecord::Base
self.table_name = 'developers'
@ -285,6 +311,17 @@ class CallbacksTest < ActiveRecord::TestCase
], david.history
end
def test_validate_on_contextual_create
david = ContextualCallbacksDeveloper.create('name' => 'David', 'salary' => 1000000)
assert_equal [
:before_validation,
:before_validation_on_create,
:validate,
:after_validation,
:after_validation_on_create
], david.history
end
def test_update
david = CallbackDeveloper.find(1)
david.save
@ -344,6 +381,18 @@ class CallbacksTest < ActiveRecord::TestCase
], david.history
end
def test_validate_on_contextual_update
david = ContextualCallbacksDeveloper.find(1)
david.save
assert_equal [
:before_validation,
:before_validation_on_update,
:validate,
:after_validation,
:after_validation_on_update
], david.history
end
def test_destroy
david = CallbackDeveloper.find(1)
david.destroy

View file

@ -995,6 +995,25 @@ class User < ActiveRecord::Base
end
```
Callbacks can also be registered to only fire on certain lifecycle events:
<ruby>
class User < ActiveRecord::Base
before_validation :normalize_name, :on => :create
# :on takes an array as well
after_validation :set_location, :on => [ :create, :update ]
protected
def normalize_name
self.name = self.name.downcase.titleize
end
def set_location
self.location = LocationService.query(self)
end
end
</ruby>
It is considered good practice to declare callback methods as protected or private. If left public, they can be called from outside of the model and violate the principle of object encapsulation.
Available Callbacks