Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Ruby Dictionary

  1. Home
  2. Ruby Dictionary
  3. method_missing / respond_to_missing? (Ruby)

method_missing / respond_to_missing? (Ruby)

In Ruby, method_missing is a hook method that fires automatically when an undefined method is called. Combined with respond_to_missing?, it enables correct implementation of dynamic methods.

Syntax

# Hook that fires when an undefined method is called.
def method_missing(method_name, *args, &block)
  # method_name: the called method name (Symbol).
  # args:        array of arguments passed.
  # block:       block passed (if any).
  super  # Call super to raise NoMethodError if not handled.
end

# Must be defined alongside method_missing to integrate with respond_to?.
def respond_to_missing?(method_name, include_private = false)
  # Return true if this object should respond to the method name.
  condition || super
end

Method / Hook Reference

Method / HookDescription
method_missing(name, *args, &block)Hook method that runs automatically when an undefined method is called.
respond_to_missing?(name, include_private)Integrates with respond_to?. Returns true if the dynamic method can respond to the given name.
respond_to?(name)Checks whether an object can respond to a given method. Delegates to respond_to_missing?.
method(name)Retrieves a Method object. Dynamic methods are also retrievable when respond_to_missing? is correctly defined.
superCalls the same method in the parent class. Always call super to raise NoMethodError when the case is not handled.

Sample Code

A basic implementation of dynamic methods combining method_missing and respond_to_missing?.

method_missing_basic.rb
# A class that retrieves character stats via dynamic methods.
# Methods starting with "power_of_" are handled dynamically.
class Fighter
  attr_reader :name, :stats

  def initialize(name, stats)
    @name  = name
    @stats = stats  # Hash like { strength: 9000, speed: 7500, ki: 8800 }.
  end

  # Fires when an undefined method is called.
  def method_missing(method_name, *args, &block)
    method_str = method_name.to_s

    if method_str.start_with?("power_of_")
      # "power_of_strength" -> looks up :strength in stats.
      stat_key = method_str.sub("power_of_", "").to_sym
      if @stats.key?(stat_key)
        return @stats[stat_key]
      end
    end

    # Always call super to raise NoMethodError for unhandled cases.
    super
  end

  # Integrates with respond_to?.
  def respond_to_missing?(method_name, include_private = false)
    method_str = method_name.to_s
    if method_str.start_with?("power_of_")
      stat_key = method_str.sub("power_of_", "").to_sym
      return @stats.key?(stat_key)
    end
    super
  end

  def to_s
    "#{@name}"
  end
end

goku   = Fighter.new("Son Goku",  { strength: 9000, speed: 9500, ki: 9900 })
vegeta = Fighter.new("Vegeta",    { strength: 8800, speed: 9000, ki: 9600 })

# Retrieve stats via dynamic methods.
puts "#{goku} strength: #{goku.power_of_strength}"   # 9000
puts "#{goku} speed: #{goku.power_of_speed}"         # 9500
puts "#{vegeta} ki: #{vegeta.power_of_ki}"           # 9600

# respond_to? works correctly.
puts goku.respond_to?(:power_of_strength)  # true
puts goku.respond_to?(:power_of_defense)   # false (no defense key in stats)
puts goku.respond_to?(:fly)               # false (not defined)
ruby method_missing_basic.rb
Son Goku strength: 9000
Son Goku speed: 9500
Vegeta ki: 9600
true
false
false

A practical example of the DynamicProxy pattern that transparently delegates method calls to another object.

method_missing_proxy.rb
# Character class for Dragon Ball.
class Character
  attr_reader :name, :race, :power_level

  def initialize(name, race, power_level)
    @name        = name
    @race        = race
    @power_level = power_level
  end

  def status
    "#{@name} (#{@race}) Power Level: #{@power_level}"
  end

  def to_s
    @name
  end
end

# DynamicProxy: delegates method calls to a Character with logging.
class LoggingProxy
  def initialize(target)
    @target = target
    @log    = []
  end

  # Delegates all unrecognized methods to the target.
  def method_missing(method_name, *args, &block)
    if @target.respond_to?(method_name)
      @log << "[LOG] #{method_name} was called."
      @target.send(method_name, *args, &block)
    else
      super
    end
  end

  def respond_to_missing?(method_name, include_private = false)
    @target.respond_to?(method_name, include_private) || super
  end

  def show_log
    puts "--- Call Log ---"
    @log.each { |entry| puts entry }
  end
end

gohan  = Character.new("Son Gohan", "Half-Saiyan", 22000)
proxy  = LoggingProxy.new(gohan)

# Call gohan's methods through the proxy.
puts proxy.name         # Son Gohan
puts proxy.race         # Half-Saiyan
puts proxy.status       # Son Gohan (Half-Saiyan) Power Level: 22000
puts proxy.respond_to?(:name)   # true
puts proxy.respond_to?(:fly)    # false

proxy.show_log
ruby method_missing_proxy.rb
Son Gohan
Half-Saiyan
Son Gohan (Half-Saiyan) Power Level: 22000
true
false
--- Call Log ---
[LOG] name was called.
[LOG] race was called.
[LOG] status was called.
[LOG] respond_to? was called.
[LOG] respond_to? was called.

A comparison of a flawed and a correct implementation, showing how omitting super makes debugging difficult.

method_missing_debug.rb
# NG: implementation without super.
# Typos silently return nil instead of raising an error.
class BadProxy
  def initialize(target)
    @target = target
  end

  def method_missing(method_name, *args, &block)
    if @target.respond_to?(method_name)
      @target.send(method_name, *args, &block)
    end
    # Without super, calling an undefined method just returns nil silently.
  end
end

piccolo = Object.new
def piccolo.name; "Piccolo"; end

# OK: implementation that always calls super for unhandled cases.
class GoodProxy
  def initialize(target)
    @target = target
  end

  def method_missing(method_name, *args, &block)
    if @target.respond_to?(method_name)
      @target.send(method_name, *args, &block)
    else
      # Always call super to raise NoMethodError.
      super
    end
  end

  def respond_to_missing?(method_name, include_private = false)
    @target.respond_to?(method_name, include_private) || super
  end
end

krilin = Object.new
def krilin.name;  "Krillin"; end
def krilin.race;  "Human";   end

proxy = GoodProxy.new(krilin)

puts proxy.name   # Krillin
puts proxy.race   # Human

begin
  proxy.power_level  # Undefined method -> raises NoMethodError.
rescue NoMethodError => e
  puts "NoMethodError: #{e.message}"
end
ruby method_missing_debug.rb
Krillin
Human
NoMethodError: undefined method 'power_level' for an instance of GoodProxy

Notes

method_missing is a central mechanism in Ruby metaprogramming. Because it fires every time an undefined method is called, it is used to build dynamic APIs such as DynamicProxy, DSL (Domain Specific Language), and ORM patterns.

When defining method_missing, respond_to_missing? must also be defined alongside it. This ensures that respond_to?, method(:xxx), and defined? correctly recognize the dynamic methods.

The most common pitfall in method_missing implementations is forgetting to call super for unhandled cases. Omitting super causes typos and calls to nonexistent methods to fail silently, making debugging very difficult. Delegating all methods without restriction also risks forwarding unintended method calls. It is safer to explicitly limit the scope of handled methods and always delegate the rest to super.

As an alternative to dynamic methods, define_method defines methods upfront, which is superior in both performance and debuggability. See module / include / extend for more on dynamic method definition.

Common Mistakes

Mistake 1: Forgetting to call super (silent failure)

When super is not called for an unhandled method name, a typo just returns nil without raising an error, making bugs harder to find.

ng_no_super.rb
class Fighter
  def initialize(name, stats)
    @name  = name
    @stats = stats
  end

  def method_missing(method_name, *args, &block)
    stat_key = method_name.to_s.sub("power_of_", "").to_sym
    if @stats.key?(stat_key)
      return @stats[stat_key]
    end
    # Without super, an unmatched method name silently returns nil.
  end
end

goku = Fighter.new("Son Goku", { strength: 9000 })
puts goku.power_of_strenght.inspect  # typo: returns nil without error
ruby ng_no_super.rb
nil

Correct approach: always call super for unhandled method names to raise NoMethodError.

ok_with_super.rb
class Fighter
  def initialize(name, stats)
    @name  = name
    @stats = stats
  end

  def method_missing(method_name, *args, &block)
    stat_key = method_name.to_s.sub("power_of_", "").to_sym
    if method_name.to_s.start_with?("power_of_") && @stats.key?(stat_key)
      return @stats[stat_key]
    end
    super
  end

  def respond_to_missing?(method_name, include_private = false)
    stat_key = method_name.to_s.sub("power_of_", "").to_sym
    (method_name.to_s.start_with?("power_of_") && @stats.key?(stat_key)) || super
  end
end

goku = Fighter.new("Son Goku", { strength: 9000 })
begin
  puts goku.power_of_strenght.inspect  # typo -> NoMethodError
rescue NoMethodError => e
  puts "NoMethodError: #{e.message}"
end
puts goku.power_of_strength  # correct name -> 9000
ruby ok_with_super.rb
NoMethodError: undefined method 'power_of_strenght' for an instance of Fighter
9000

Mistake 2: Forgetting to define respond_to_missing?

When only method_missing is defined without respond_to_missing?, respond_to? returns false for dynamic methods, causing external code to wrongly conclude the object cannot respond to those methods.

ng_no_respond_to_missing.rb
class Fighter
  def initialize(name, stats)
    @name  = name
    @stats = stats
  end

  def method_missing(method_name, *args, &block)
    stat_key = method_name.to_s.sub("power_of_", "").to_sym
    if method_name.to_s.start_with?("power_of_") && @stats.key?(stat_key)
      return @stats[stat_key]
    end
    super
  end
  # respond_to_missing? is not defined
end

goku = Fighter.new("Son Goku", { strength: 9000 })
puts goku.power_of_strength                   # 9000 (method works)
puts goku.respond_to?(:power_of_strength)     # false (incorrect result)
ruby ng_no_respond_to_missing.rb
9000
false

Correct approach: implement the same condition in respond_to_missing? as in method_missing.

ok_respond_to_missing.rb
class Fighter
  def initialize(name, stats)
    @name  = name
    @stats = stats
  end

  def method_missing(method_name, *args, &block)
    stat_key = method_name.to_s.sub("power_of_", "").to_sym
    if method_name.to_s.start_with?("power_of_") && @stats.key?(stat_key)
      return @stats[stat_key]
    end
    super
  end

  def respond_to_missing?(method_name, include_private = false)
    stat_key = method_name.to_s.sub("power_of_", "").to_sym
    (method_name.to_s.start_with?("power_of_") && @stats.key?(stat_key)) || super
  end
end

goku = Fighter.new("Son Goku", { strength: 9000 })
puts goku.power_of_strength                   # 9000
puts goku.respond_to?(:power_of_strength)     # true
puts goku.respond_to?(:power_of_defense)      # false (no defense key in stats)
ruby ok_respond_to_missing.rb
9000
true
false

Mistake 3: Infinite loop (calling an undefined method inside method_missing)

Calling an undefined method on the same object inside method_missing triggers method_missing again, causing an infinite loop.

ng_infinite_loop.rb
class Fighter
  def initialize(name)
    @name = name
  end

  def method_missing(method_name, *args, &block)
    # log_call is undefined, so method_missing is triggered again here (infinite loop).
    log_call(method_name)
    super
  end

  def respond_to_missing?(method_name, include_private = false)
    super
  end
end

goku = Fighter.new("Son Goku")
goku.fly  # => SystemStackError: stack level too deep
ruby ng_infinite_loop.rb
ng_infinite_loop.rb:7:in 'Fighter#method_missing': stack level too deep (SystemStackError)

Correct approach: only call already-defined methods inside method_missing.

ok_no_loop.rb
class Fighter
  def initialize(name)
    @name = name
  end

  def method_missing(method_name, *args, &block)
    # Use the already-defined puts for logging.
    puts "[LOG] #{method_name} was called (undefined)"
    super
  end

  def respond_to_missing?(method_name, include_private = false)
    super
  end
end

goku = Fighter.new("Son Goku")
begin
  goku.fly
rescue NoMethodError => e
  puts "NoMethodError: #{e.message}"
end
ruby ok_no_loop.rb
[LOG] fly was called (undefined)
NoMethodError: undefined method 'fly' for an instance of Fighter

If you find any errors or copyright issues, please .