class method self.method_missing

Ruby on Rails 2.2.3

Since v2.2.3 Last seen in v3.1.12 Private

Available in: v2.2.3 v2.3.18 v3.0.20 v3.1.12

Signature

self.method_missing(method_id, *arguments, &block)

Enables dynamic finders like find_by_user_name(user_name) and find_by_user_name_and_password(user_name, password) that are turned into find(:first, :conditions => [“user_name = ?”, user_name]) and find(:first, :conditions => [“user_name = ? AND password = ?”, user_name, password]) respectively. Also works for find(:all) by using find_all_by_amount(50) that is turned into find(:all, :conditions => [“amount = ?”, 50]).

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

This also enables you to initialize a record if it is not found, such as find_or_initialize_by_amount(amount) or find_or_create_by_user_and_password(user, password).

Each dynamic finder or initializer/creator is also defined in the class after it is first invoked, so that future attempts to use it do not run through method_missing.

Parameters

method_id req
arguments rest
block block
Source
# File activerecord/lib/active_record/base.rb, line 1777
        def method_missing(method_id, *arguments, &block)
          if match = DynamicFinderMatch.match(method_id)
            attribute_names = match.attribute_names
            super unless all_attributes_exists?(attribute_names)
            if match.finder?
              finder = match.finder
              bang = match.bang?
              self.class_eval %{
                def self.#{method_id}(*args)
                  options = args.extract_options!
                  attributes = construct_attributes_from_arguments([:#{attribute_names.join(',:')}], args)
                  finder_options = { :conditions => attributes }
                  validate_find_options(options)
                  set_readonly_option!(options)

                  #{'result = ' if bang}if options[:conditions]
                    with_scope(:find => finder_options) do
                      find(:#{finder}, options)
                    end
                  else
                    find(:#{finder}, options.merge(finder_options))
                  end
                  #{'result || raise(RecordNotFound)' if bang}
                end
              }, __FILE__, __LINE__
              send(method_id, *arguments)
            elsif match.instantiator?
              instantiator = match.instantiator
              self.class_eval %{
                def self.#{method_id}(*args)
                  guard_protected_attributes = false

                  if args[0].is_a?(Hash)
                    guard_protected_attributes = true
                    attributes = args[0].with_indifferent_access
                    find_attributes = attributes.slice(*[:#{attribute_names.join(',:')}])
                  else
                    find_attributes = attributes = construct_attributes_from_arguments([:#{attribute_names.join(',:')}], args)
                  end

                  options = { :conditions => find_attributes }
                  set_readonly_option!(options)

                  record = find(:first, options)

                  if record.nil?
                    record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) }
                    #{'yield(record) if block_given?'}
                    #{'record.save' if instantiator == :create}
                    record
                  else
                    record
                  end
                end
              }, __FILE__, __LINE__
              send(method_id, *arguments, &block)
            end
          else
            super
          end
        end

Defined in activerecord/lib/active_record/base.rb line 1777 · View on GitHub · Improve this page · Find usages on GitHub

Defined in ActiveRecord::Base

Type at least 2 characters to search.

↑↓ navigate · open · esc close