开发者

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):

  1. Downloaded Rails v2.3.8 from github and unzipped it.
  2. grepp'ed for :if in all .rb files
  3. 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].
  4. Google'd for that comment. Found it in a google cache.
  5. Found that the comment/addition was made on 05/21/05 10:57:18 by david
  6. Located date 2005-05-21 on rails github history on page 546:
  7. Got an inkling of how the :if works
  8. Found that the code that commit referred to was no longer existing in v2.3.8. had to find latest location of that code
  9. grepp'ed :if again and went though each file that felt "good". came to activesupport/lib/active_support/callbacks.rb
  10. searched for :if in the file and it was found in only one location, in the method should_run_callback.
  11. Posted answer
  12. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜