NoMethodError

It left that method somewhere, but it's not quite sure where...

Ruby's NoMethodError class

NoMethodError is raised when a method is called on a receiver which doesn't have it defined and also fails to respond with method_missing:

"creature".rawr

raises the exception:

NoMethodError: undefined method `rawr' for "creature":String

Superclass

NameError

Methods

  • args
  • private_call?

Enemies

Honeybadger

» Undefined method for nil:NilClass

First off, nil is a creature in its own rite, and is a common source of confusion when debugging Ruby programs. A NoMethodError resulting from attempting to call a method on nil is the most common error in Ruby.

The problem often arises when unexpected input is passed into a class or method. For example, say we want to capture a creature:

class Cage
  attr_accessor :creature

  def initialize(creature = nil)
    self.creature = creature # We forget to set a default!
  end

  def rawr
    creature.rawr
  end
end

cage = Cage.new
cage.rawr # => NoMethodError: undefined method `rawr' for nil:NilClass

Not only did we fail to capture our creature, we just spawned the scariest creature of all: an undefined method for nil NoMethodError!

» Now, where'd I put that method?

When you call a method on an object and Ruby can't find it, it raises NoMethodError. For example:

class Creature
end

creature = Creature.new
creature.rawr # => NoMethodError: undefined method `rawr' for #<Creature:0x0055e6fb99e390>

The path Ruby takes to arrive at a NoMethodError exception is a winding one. Before throwing it's hands in the air and giving up, Ruby searches extensively for the method:

» 1. First, it looks on the singleton class

A singleton method is like a normal Ruby method, but it's defined on an instance instead of on a class:

class Creature
  def rawr
    'rawr!'
  end
end

creature = Creature.new

def creature.rawr
  'raaaaawr!'
end

creature.rawr # => 'raaaaawr!'

» 2. Next, it looks on modules which extend the singleton

Similar to adding a method to an instance of a class, Ruby can also extend and instance of an object with a module's methods. This is a way to define a group of singleton methods at once:

module LoudCreature
  def rawr
    'raaaaawr!'
  end
end

creature = Creature.new
creature.extend(LoudCreature)

creature.rawr # => 'raaaaawr!'

If the instance is extended multiple times, Ruby works back from the most recently extended module to find the method you asked for:

module QuietCreature
  def rawr
    'purrrrr :3'
  end
end

creature = Creature.new
creature.extend(LoudCreature)
creature.extend(QuietCreature)

creature.rawr # => 'purrrrr :3'

» 3. Now Ruby looks on the class

You may have been expecting this to be the first place Ruby would look, but as we saw, the singleton comes first. If the method doesn't exist there, Ruby looks for the method on the class:

creature = Creature.new
creature.rawr # => 'rawr!'

» 4. Modules that were included when defining the class

Next up, Ruby looks for the method in any modules that are included in the class (commonly called "Mixins"), in reverse order of inclusion:

class Creature
  include LoudCreature
  include QuietCreature
end

creature = Creature.new
creature.rawr # => 'purrrrr :3'

» Prepend works differently in Ruby 2.0

Ruby 2.0 introduced prepend, which works a bit differently than include. Instead of looking in the class first, Ruby searches the module before the class:

class Creature
  prepend LoudCreature

  def rawr
    'rawr!'
  end
end

creature = Creature.new
creature.rawr # => 'raaaaawr!'

» 5. Ruby Meets the Parents

OK, so the instance and class definitely don't have the method. The next place Ruby looks is the superclass of the object's class, repeating steps 3-5 (there are no new instances involved from this point on):

class Beast
  def rawr
    'hurrrrrrrr!'
  end
end

class Creature < Beast
  # Method defined on superclass
end

creature = Creature.new
creature.rawr # => 'hurrrrrrrr!'

» 6. A Method to Find Missing Methods

Ruby searches the ancestors of the class all the way up to BasicObject. If the method is still missing, Ruby goes back to the original class and calls a special method: method_missing:

class Creature
  def method_missing(method, *args, &block)
    "I haven't learned to #{method} yet :("
  end
end

creature = Creature.new
creature.rawr # => "I haven't learned to rawr yet :("
creature.rawor # => "I haven't learned to rawor yet :("

If the class doesn't define method_missing, Ruby repeats the search we just explored, but this time for method_missing:

module Beast
  def method_missing(method, *args, &block)
    "I haven't learned to #{method} yet :("
  end
end

class Creature
  include Beast
end

creature = Creature.new
creature.rawr # => "I haven't learned to rawr yet :("