How does ActiveRecord implement `:if => ...` on validations
I've been looking through the ActiveRecord source to find out how :if => proc_or_method_name
works on ActiveRecord validations, but the only instances of :if
in the source are in the comments explaining how the feature should be called.
For example, you can have a line like the following in a model:
validates_presence_of :name, :if => :nameable?
and the validation only gets checked if 开发者_如何学运维the nameable?
method returns a truthy value for the given model.
Where is this functionality actually defined, as I can't find this behaviour anywhere in the (Rails2) source?
The :if
option is checked for in the file activesupport\lib\active_support\callbacks.rb
.
The method should_run_callback
is called to check if the callback should be executed or not.
Look also at how the callback chain is processed, starting from the run_callbacks
method in the same file.
Some code from v2.3.8 of that file is:
def should_run_callback?(*args)
[options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
end
And here is how I found out (in case anyone is interested):
- Downloaded Rails v2.3.8 from github and unzipped it.
- grepp'ed for
:if
in all .rb files - In a
activerecord/CHANGELOG
, located a comment that mentioned:
Added the :if option to all validations that can either use a block or a method pointer to determine whether the validation should be run or not. #1324 [Duane Johnson/jhosteny]. - Google'd for that comment. Found it in a google cache.
- Found that the comment/addition was made on 05/21/05 10:57:18 by david
- Located date 2005-05-21 on rails github history on page 546:
- Got an inkling of how the
:if
works - Found that the code that commit referred to was no longer existing in v2.3.8. had to find latest location of that code
- grepp'ed
:if
again and went though each file that felt "good". came toactivesupport/lib/active_support/callbacks.rb
- searched for
:if
in the file and it was found in only one location, in the methodshould_run_callback
. - Posted answer
- Crossed fingers and waited for bounty. :D
That was fun!
As of Rails 3, ActiveRecord callbacks are defined in active_record/callbacks.rb, but because an ActiveRecord model inherits from ActiveModel, then you should also look at the active_model/callbacks.rb file.
The Callback feature itself is a separate component. In fact, ActionController before/after filters are callbacks, actually. For this reason, the callback system is a module defined in ActiveSupport::Callbacks.
Merge altogether these 3 pieces and you get the ActiveRecord callbacks feature.
精彩评论