Question

Calling an Overridden Monkey-Patched Method in Ruby

rubymonkeypatching

Question

In Ruby, if I monkey patch a method in a class, how can I still call the original implementation from the new method?

I am looking for something similar to super, but for a method that I redefine in the same class.

For example:

class Foo
  def bar
    "Hello"
  end
end

class Foo
  def bar
    super() + " World"
  end
end

Foo.new.bar # expected: "Hello World"

Is there a way to call the previous version of bar after reopening the class and redefining it?

Short Answer

By the end of this page, you will understand why super does not call the previous version of a monkey-patched method in the same Ruby class, and how to correctly preserve and call the original method using techniques like alias_method. You will also see safer patterns, common mistakes, and how this works in real Ruby codebases.

Concept

In Ruby, monkey patching means reopening a class and changing or replacing its methods. This is powerful, but it also means the new method definition usually replaces the old one.

A common beginner question is: If I redefine a method, can I still call the old version from the new one?

The key idea is:

  • super calls a method with the same name in the ancestor chain
  • It does not call the method definition that was previously written in the same class
  • When you redefine a method in the same class, the old definition is overwritten unless you save it first

So in this case:

class Foo
  def bar
    "Hello"
  end
end

class Foo
  def bar
    super + " World"
  end
end

super will look for bar in Foo's superclass, not for the earlier bar that used to exist in Foo itself.

That is why monkey patching often uses alias_method:

  1. Save the original method under another name
  2. Redefine the method
  3. Call the aliased original inside the new version

This matters because Ruby developers often patch existing behavior in:

  • legacy applications
  • gems
  • framework classes
  • test environments
  • debugging or instrumentation code

If you patch without preserving the original method, you may lose useful behavior or introduce hard-to-find bugs.

Mental Model

Think of a Ruby class like a whiteboard with method names written on it.

If Foo has a method named bar, the whiteboard says:

  • bar -> "Hello"

When you reopen the class and define bar again, you erase the old line and write a new one:

  • bar -> new implementation

The old writing is gone unless you copied it somewhere first.

Now think of super as walking upstairs to ask a parent class for help. It does not look at what was previously erased and rewritten on the same whiteboard. It only checks parent classes or included modules in the method lookup chain.

So:

  • redefining a method in the same class = replacing the current label
  • super = ask the next ancestor, not the old version in the same class
  • alias_method = make a backup copy before replacing it
Take Quiz

Syntax and Examples

Basic pattern with alias_method

class Foo
  def bar
    "Hello"
  end
end

class Foo
  alias_method :bar_without_patch, :bar

  def bar
    bar_without_patch + " World"
  end
end

puts Foo.new.bar
# Hello World

What this does

  • alias_method :bar_without_patch, :bar saves the original bar
  • The new bar method replaces the old one
  • Inside the new bar, you call bar_without_patch

Why super does not work here

class Foo
  def bar
    "Hello"
  end
end

class Foo
  def bar
    super + " World"
  end
end

This raises an error unless a superclass defines bar:

# NoMethodError: super: no superclass method `bar`

That is because the earlier bar in Foo is not treated like a parent method.

Example with arguments

class Greeter
  def greet(name)
    "Hello, #{name}"
  end
end

class Greeter
  alias_method :original_greet, :greet

  def greet(name)
    original_greet(name) + "!"
  end
end

puts Greeter.new.greet("Sam")
# Hello, Sam!

Example using modules and prepend

In modern Ruby, a cleaner alternative is often prepend:

class Foo
  def bar
    "Hello"
  end
end

module FooPatch
  def bar
    super + " World"
  end
end

Foo.prepend(FooPatch)

puts Foo.new.bar
# Hello World

Here super works because the module becomes part of the method lookup chain.

Step by Step Execution

Consider this example:

class Foo
  def bar
    "Hello"
  end
end

class Foo
  alias_method :original_bar, :bar

  def bar
    original_bar + " World"
  end
end

result = Foo.new.bar
puts result

Step-by-step

  1. Ruby defines class Foo
  2. Method bar is created and returns "Hello"
  3. Ruby reopens class Foo
  4. alias_method :original_bar, :bar creates a second name for the current bar
    • now both bar and original_bar refer to the original implementation
  5. A new bar method is defined
    • this replaces the old bar
    • original_bar still points to the saved version
  6. Foo.new.bar is called
  7. Ruby runs the new bar
  8. Inside it, original_bar is called
  9. original_bar returns "Hello"
  10. The new method adds " World"
  11. Final result is "Hello World"

Trace

original_bar   # => "Hello"
"Hello" + " World"
# => "Hello World"

Real World Use Cases

Monkey patching with access to the original method appears in several real situations:

Logging and instrumentation

You may want to keep the original behavior but add logging.

class ApiClient
  def fetch
    "data"
  end
end

class ApiClient
  alias_method :original_fetch, :fetch

  def fetch
    puts "Fetching started"
    result = original_fetch
    puts "Fetching finished"
    result
  end
end

Fixing behavior in third-party code

Sometimes a gem has a bug and you need a temporary patch while still using most of its original method.

Adding validation

You can wrap an existing method with extra checks.

class User
  def set_age(age)
    @age = age
  end
end

class User
  alias_method :original_set_age, :set_age

  def set_age(age)
    raise ArgumentError, "age must be positive" if age < 0
    original_set_age(age)
  end
end

Performance measurement

Developers often wrap methods to measure duration without rewriting all logic.

Testing and debugging

In test code, methods are sometimes patched to observe calls or inject extra behavior.

Take Quiz

Real Codebase Usage

In real Ruby projects, developers usually try to avoid direct monkey patching unless necessary, but when they do use it, they often follow some patterns.

Preserve the original behavior

If the original method still matters, save it before redefining it:

alias_method :original_method_name, :method_name

Prefer prepend for cleaner extension

A common modern pattern is:

module Patch
  def perform(*args)
    puts "before"
    result = super
    puts "after"
    result
  end
end

SomeClass.prepend(Patch)

This is often easier to reason about than alias chains.

Use guard clauses

When wrapping a method, developers often validate inputs early:

def save(data)
  return false if data.nil?
  original_save(data)
end

Keep patches small and focused

Good patches usually do one thing:

  • add logging
  • validate input
  • transform output
  • handle edge cases

Name aliases clearly

Common alias names include:

  • original_bar
  • bar_without_logging
  • bar_before_patch

Clear names make maintenance easier.

Be careful in shared code

Monkey patches affect all uses of that class in the running process. In a large app, that can create surprising side effects.

Common Mistakes

Mistake 1: Expecting super to call the old method in the same class

Broken code:

class Foo
  def bar
    "Hello"
  end
end

class Foo
  def bar
    super + " World"
  end
end

Why it fails:

  • super looks in ancestors
  • it does not call the earlier bar that existed in Foo

Fix:

class Foo
  alias_method :original_bar, :bar

  def bar
    original_bar + " World"
  end
end

Mistake 2: Creating infinite recursion

Broken code:

class Foo
  def bar
    bar + " World"
  end
end

Why it fails:

  • bar calls itself again and again
  • this causes a stack overflow

Fix:

Call the aliased original method instead.

Mistake 3: Aliasing after redefining

Broken idea:

class Foo
  def bar
    "Hello"
  end
end

class Foo
  def bar
    "Patched"
  end

  alias_method :original_bar, :bar
end

Why it fails:

  • now original_bar points to the new method, not the original one

Fix:

Alias first, then redefine.

Mistake 4: Forgetting method arguments

Broken code:

class Greeter
  def greet(name)
    "Hello, #{name}"
  end
end

class Greeter
  alias_method :original_greet, :greet

  def greet(name)
    original_greet + "!"
  end
end

Why it fails:

  • original_greet expects name

Fix:

def greet(name)
  original_greet(name) + "!"
end

Mistake 5: Patching core classes carelessly

You can monkey patch classes like String or Array, but doing so may break other libraries or confuse teammates.

Avoid this unless you truly need it and understand the impact.

Comparisons

super vs alias_method vs prepend

TechniqueWhat it callsBest use caseMain limitation
superSame method in ancestor chainInheritance or modulesDoes not call previous method in same class
alias_methodSaved copy of original methodDirect monkey patchingCan become messy with multiple patches
prependOriginal method through ancestor lookupCleaner wrapping/extending behaviorRequires using a module

Redefining in same class vs subclassing

ApproachWhat happensTypical use
Reopen same classReplaces method globallyMonkey patching existing class
Create subclassNew behavior only in subclassSafer customization

Example comparison

Using alias_method

class Foo
  def bar
    "Hello"
  end
end

class Foo
  alias_method :original_bar, :bar

  def bar
    original_bar + " World"
  end
end

Using prepend

class Foo
  def bar
    "Hello"
  end
end

module Patch
  def bar
    super + " World"
  end
end

Foo.prepend(Patch)

If you are working in modern Ruby and can choose the design, prepend is often the cleaner option.

Take Quiz

Cheat Sheet

Quick reference

super

def method_name
  super
end
  • Calls the same method in a superclass or prepended/included ancestor
  • Does not call the old version of a method redefined in the same class

Save original method before monkey patching

class Foo
  alias_method :original_bar, :bar

  def bar
    original_bar + " World"
  end
end

Important rule

  • Alias first, redefine second

With arguments

alias_method :original_greet, :greet

def greet(name)
  original_greet(name) + "!"
end

Cleaner alternative with prepend

module Patch
  def bar
    super + " World"
  end
end

Foo.prepend(Patch)

Common pitfalls

  • Using super in the same class and expecting old behavior
  • Calling the new method from itself and causing recursion
  • Forgetting to pass arguments to the aliased method
  • Aliasing after redefining the method

Rule of thumb

  • Need the previous method in the same class? Use alias_method
  • Want a cleaner extension layer? Use prepend

FAQ

Why does super not work when I redefine a method in the same Ruby class?

Because super only looks in the method lookup chain above the current class or module. It does not remember the old method body that was replaced in the same class.

How do I call the original method after monkey patching in Ruby?

Save it first with alias_method, then call the alias inside the new method.

Is alias_method better than super for monkey patching?

For redefining a method in the same class, yes. super is for ancestor methods, while alias_method lets you preserve the original implementation before replacing it.

What is the modern Ruby alternative to alias-based monkey patching?

Module#prepend is often preferred because it works naturally with super and keeps the method lookup chain clearer.

Can monkey patching be dangerous?

Yes. It changes behavior globally for that class in the current process, which can affect unrelated parts of an application.

Should I monkey patch a gem or Ruby core class?

Only when necessary. Prefer safer alternatives like wrappers, subclasses, composition, or prepend if they fit your use case.

Can I monkey patch instance methods and class methods the same way?

The idea is similar, but the syntax differs because class methods live on the singleton class.

Take Quiz

Mini Project

Description

Build a small Ruby class that formats messages, then monkey patch it to add a prefix while still keeping the original behavior. This demonstrates how to preserve an instance method before redefining it.

Goal

Create a monkey patch that extends an existing method without losing the original implementation.

Requirements

  • Create a class with an instance method that returns a basic message.
  • Preserve the original method before redefining it.
  • Redefine the method so it adds extra text to the original result.
  • Print the final result to confirm the patch works.
Take Quiz

Keep learning

Related questions

View more