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:
supercalls 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:
- Save the original method under another name
- Redefine the method
- 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 classalias_method= make a backup copy before replacing it
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, :barsaves the originalbar- The new
barmethod replaces the old one - Inside the new
bar, you callbar_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
- Ruby defines class
Foo - Method
baris created and returns"Hello" - Ruby reopens class
Foo alias_method :original_bar, :barcreates a second name for the currentbar- now both
barandoriginal_barrefer to the original implementation
- now both
- A new
barmethod is defined- this replaces the old
bar original_barstill points to the saved version
- this replaces the old
Foo.new.baris called- Ruby runs the new
bar - Inside it,
original_baris called original_barreturns"Hello"- The new method adds
" World" - 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.
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_barbar_without_loggingbar_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:
superlooks in ancestors- it does not call the earlier
barthat existed inFoo
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:
barcalls 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_barpoints 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_greetexpectsname
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
| Technique | What it calls | Best use case | Main limitation |
|---|---|---|---|
super | Same method in ancestor chain | Inheritance or modules | Does not call previous method in same class |
alias_method | Saved copy of original method | Direct monkey patching | Can become messy with multiple patches |
prepend | Original method through ancestor lookup | Cleaner wrapping/extending behavior | Requires using a module |
Redefining in same class vs subclassing
| Approach | What happens | Typical use |
|---|---|---|
| Reopen same class | Replaces method globally | Monkey patching existing class |
| Create subclass | New behavior only in subclass | Safer 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.
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
superin 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.
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.
Keep learning
Related questions
Add a Default Value to an Existing Column in a Rails Migration
Learn how to add or change a default value on an existing database column using Rails Active Record migrations safely.
Calling a Class Method from an Instance in Ruby
Learn how to call a class method from an instance in Ruby using self.class, with examples, pitfalls, and practical usage patterns.
Check Whether a Value Is an Array in Ruby and Count Items
Learn how to test whether a value is an Array in Ruby and count its elements with is_a?, length, size, and count.