How method_missing and respond_to_missing? Work in Ruby
method_missing and respond_to_missing? are two of Ruby’s most powerful metaprogramming tools. The method_missing hook intercepts calls to methods that do not exist, while respond_to_missing? keeps your objects honest about what they can handle. Together they enable dynamic interfaces, DSLs, and flexible message handling.
Key takeaways
method_missinglets you intercept undefined method calls and decide what should happen next.respond_to_missing?keepsrespond_to?accurate, which matters for debugging and introspection.- DSLs, delegation, and dynamic finders are all common uses of this pattern.
supershould still be called when the object cannot handle a method.method_missingis flexible, but explicit methods are usually easier to maintain.
If you want the short version, think of method_missing as a catch-all and respond_to_missing? as the honesty check that goes with it. Together they let you build dynamic interfaces without confusing callers about what the object can actually do.
When should you use method_missing?
Use method_missing when the method names are genuinely dynamic and the pattern is obvious to the caller. It works well for small DSLs, delegated APIs, and library code that needs to translate method names into data lookups. It is a poor fit for stable public APIs where explicit methods would be easier to test and easier to read.
That tradeoff matters because dynamic dispatch hides intent. A normal method call tells the reader exactly which method exists. A method_missing call asks the reader to inspect the implementation before they know what happens. Use the flexibility when it buys you something real, not just because Ruby allows it.
How method_missing Works
When you call a method that doesn’t exist on an object, Ruby normally raises a NoMethodError. However, if the object defines method_missing, that gets called instead, giving you a chance to handle the unknown method dynamically.
class DynamicRecorder
def method_missing(method_name, *args, &block)
puts "Called: #{method_name} with #{args.inspect}"
# You can store these calls, forward them, or do anything else
end
end
recorder = DynamicRecorder.new
recorder.foo(1, 2, 3) # => Called: foo with [1, 2, 3]
recorder.bar # => Called: bar with []
The first argument is the method name as a symbol, followed by any arguments, and optionally a block. The handler receives every call that did not match a defined method, which makes it a powerful catch-all for translating method names into actions, lookups, or forwarded calls.
This makes the pattern useful for translating method names into a lookup or a command. The code can stay compact because the handler decides whether to respond, delegate, or raise. That flexibility is the main reason method_missing powers so many Ruby DSLs.
Use cases
1. Building DSLs
method_missing shines when creating domain-specific languages:
class HtmlBuilder
def method_missing(tag_name, *args, &block)
content = block ? block.call : ""
attrs = args.first || {}
attr_string = attrs.map { |k, v| "#{k}='#{v}'" }.join(" ")
"<#{tag_name} #{attr_string}>#{content}</#{tag_name}>"
end
end
builder = HtmlBuilder.new
puts builder.div(class: "container") do
builder.p("Hello, world!")
end
# => <div class='container'><p>Hello, world!</p></div>
The DSL pattern works because the tag names do not need to be defined in advance. Any valid tag name the caller invents becomes a call to method_missing, which turns it into an HTML element. The block captures nested content and the attributes hash lets the caller pass CSS classes and other properties.
The real strength of this pattern is that the caller can stay pleasantly small while the implementation does the translation work. A method like find_by_email can become a lookup, a query, or a cache fetch without the caller needing to know which mechanism is underneath.
2. Forwarding to other objects
You can use method_missing to delegate method calls:
class User
attr_reader :name, :email
def initialize(name, email)
@name = name
@email = email
end
end
class UserPresenter
def initialize(user)
@user = user
end
def method_missing(method, *args, &block)
@user.send(method, *args, &block)
end
end
user = User.new("Alice", "alice@example.com")
presenter = UserPresenter.new(user)
puts presenter.name # => Alice
puts presenter.email # => alice@example.com
Delegation through method_missing keeps the presenter thin. Instead of defining a separate method for every attribute the user model might expose, the presenter forwards calls it does not recognize directly to the wrapped object. That works well when the delegate interface is stable and the presenter only needs to add a small layer on top.
3. ActiveRecord-like associations
Rails uses method_missing to enable methods like user.posts without explicitly defining them:
class Post
def self.find_by_author(author)
# Simulated query
["Post by #{author}"]
end
end
class AuthorProxy
def method_missing(method_name, *args, &block)
if method_name.to_s.end_with?("s")
# Assume plural method names are collections (e.g., posts)
model = method_name.to_s.singularize.capitalize
puts "Looking up #{model} records..."
Object.const_get(model).find_by_author(args.first)
else
super
end
end
end
Why respond_to_missing? matters
When you override method_missing, the default respond_to? still returns false for methods you’re handling:
class Greeter
def method_missing(name, *args)
"Hello, #{name}!"
end
end
greeter = Greeter.new
greeter.alice # => "Hello, alice!"
greeter.respond_to?(:alice) # => false - WRONG!
That false result is wrong because the object can actually handle the alice message. When method_missing is defined without the companion respond_to_missing?, Ruby’s reflection API sees a gap between what the object can do and what it claims it can do. That gap causes problems in test frameworks, serializers, and any code that checks respond_to? before calling a method.
This breaks the principle of least surprise. Users expect respond_to? to match method_missing behavior, especially when they are building reflection-heavy code or libraries that inspect object capabilities. Override respond_to_missing? to fix this:
class Greeter
def method_missing(name, *args)
if name.to_s =~ /\A[a-z_]+\z/
"Hello, #{name}!"
else
super
end
end
def respond_to_missing?(name, include_private = false)
name.to_s =~ /\A[a-z_]+\z/ || super
end
end
greeter = Greeter.new
greeter.alice # => "Hello, alice!"
greeter.respond_to?(:alice) # => true - CORRECT!
The include_private parameter defaults to false. Set it to true if you’re also handling private method calls via method_missing. The respond_to_missing? override should mirror the same guard logic you use in method_missing so that respond_to? only returns true for the exact names your dynamic handler can process.
That small method is what keeps the abstraction honest. If the object says it can respond to a name, other code can make decisions based on that promise. If it lies, bugs become harder to track down.
Performance considerations
Every call to an undefined method goes through method_missing, which is slower than calling a defined method directly. If you’re building performance-critical code:
# Instead of this:
def method_missing(method, *args)
send(method, *args) # Can cause infinite recursion!
end
# Define respond_to_missing? to avoid infinite loops:
def respond_to_missing?(method, include_private = false)
true
end
This example is intentionally blunt. The important lesson is that method_missing should be the exception path, not the default path for every action in your code. If a method will be called frequently, define it explicitly or generate it ahead of time.
Common Gotchas
Infinite Recursion
Avoid calling the method inside method_missing without a guard:
# BAD - causes infinite recursion
def method_missing(method, *args)
send(method, *args) # Calls itself forever!
end
swallow_errors silently
Don’t silently swallow all errors, it hides bugs:
# BAD practice
def method_missing(*)
# Swallowing everything hides real bugs
end
Always Call super
When you can’t handle a method, call super to preserve normal error behavior:
def method_missing(method_name, *args, &block)
if can_handle?(method_name)
handle(method_name, *args, &block)
else
super # Preserves NoMethodError for unhandled methods
end
end
Best Practices
- Always define
respond_to_missing?when you overridemethod_missing - Be specific about which methods you handle (use guards/patterns)
- Call
superfor methods you don’t handle - Document what dynamic methods your class supports
- Consider
define_methodfor frequently-called methods as an optimization
Frequently asked questions
Is method_missing the same as dynamic dispatch?
It is one form of dynamic dispatch, but the important difference is that it handles calls that were not defined in advance. That makes it more flexible than a normal method definition, but also harder to search for in a codebase.
Should I always implement respond_to_missing??
Yes, if your method_missing handles more than a toy example. It keeps respond_to? truthful, which prevents confusion for other code and for future maintainers.
What is the safer alternative to method_missing?
If the set of methods is known ahead of time, prefer define_method or plain method definitions. They are easier to test, easier to autocomplete, and easier to understand at a glance.
Summary
method_missing enables flexible, dynamic interfaces in Ruby, from DSLs to delegation to Rails-like associations. But with great power comes the responsibility to implement respond_to_missing?, keeping your objects’ interface consistent and predictable. Together, these methods let you build expressive APIs while maintaining Ruby’s duck typing guarantees.
Mastering these methods opens up advanced metaprogramming patterns. You’ll be able to create fluent interfaces that feel native to Ruby, build internal DSLs that read like plain English, and implement delegation patterns that would otherwise require significant boilerplate. The key is restraint: use these tools when they genuinely simplify your code, not just because they’re available.
Remember that every abstraction has a cost. Dynamic method resolution makes debugging harder, complicates static analysis, and can mask naming typos that would otherwise be caught at compile time. Use method_missing for genuine flexibility, but prefer explicit methods when the interface is stable and well-understood.
Conclusion
method_missing is most useful when the method name itself carries the meaning. That is why it fits DSLs, delegation, and dynamic finders so well. The cost is that the code becomes less obvious to readers and to tooling, so the best implementations keep the dynamic part as small and explicit as possible.
When in doubt, start with a plain method or define_method. Reach for method_missing when the pattern is truly open-ended and the caller benefits from a flexible interface. That balance gives you the Ruby magic without turning the class into a guessing game.
See Also
- ruby-blocks-procs-lambdas — Understanding Ruby’s blocks, procs, and lambdas
- ruby-metaprogramming-basics — Core metaprogramming concepts in Ruby
- ruby-open-classes — Opening and modifying classes at runtime