Module: ActiveRecord::DynamicMatchers

Included in:
Base
Defined in:
activerecord/lib/active_record/dynamic_matchers.rb

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_id, *arguments, &block) ⇒ Object (private)

Enables dynamic finders like User.find_by_user_name(user_name) and <tt>User.scoped_by_user_name(user_name). Refer to Dynamic attribute-based finders section at the top of this file for more detailed information.

It's even possible to use all the additional parameters to find. For example, the full interface for find_all_by_amount is actually find_all_by_amount(amount, options).

Each dynamic finder using scoped_by_* is also defined in the class after it is first invoked, so that future attempts to use it do not run through method_missing.


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'activerecord/lib/active_record/dynamic_matchers.rb', line 24

def method_missing(method_id, *arguments, &block)
  if match = (DynamicFinderMatch.match(method_id) || DynamicScopeMatch.match(method_id))
    attribute_names = match.attribute_names
    super unless all_attributes_exists?(attribute_names)
    if !(match.is_a?(DynamicFinderMatch) && match.instantiator? && arguments.first.is_a?(Hash)) && arguments.size < attribute_names.size
      method_trace = "#{__FILE__}:#{__LINE__}:in `#{method_id}'"
      backtrace = [method_trace] + caller
      raise ArgumentError, "wrong number of arguments (#{arguments.size} for #{attribute_names.size})", backtrace
    end
    if match.respond_to?(:scope?) && match.scope?
      self.class_eval <<-METHOD, __FILE__, __LINE__ + 1
        def self.#{method_id}(*args)                                    # def self.scoped_by_user_name_and_password(*args)
          attributes = Hash[[:#{attribute_names.join(',:')}].zip(args)] #   attributes = Hash[[:user_name, :password].zip(args)]
                                                                        #
          scoped(:conditions => attributes)                             #   scoped(:conditions => attributes)
        end                                                             # end
      METHOD
      send(method_id, *arguments)
    elsif match.finder?
      options = arguments.extract_options!
      relation = options.any? ? scoped(options) : scoped
      relation.send :find_by_attributes, match, attribute_names, *arguments, &block
    elsif match.instantiator?
      scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
    end
  else
    super
  end
end

Instance Method Details

#respond_to?(method_id, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)

3
4
5
6
7
8
9
10
11
# File 'activerecord/lib/active_record/dynamic_matchers.rb', line 3

def respond_to?(method_id, include_private = false)
  if match = DynamicFinderMatch.match(method_id)
    return true if all_attributes_exists?(match.attribute_names)
  elsif match = DynamicScopeMatch.match(method_id)
    return true if all_attributes_exists?(match.attribute_names)
  end

  super
end