Question
In Ruby, how can you stop execution from inside a block and return from the outer method?
For example:
class Bar
def do_things
Foo.some_method(x) do |x|
y = x.do_something
return y_is_bad if y.bad?
y.do_something_else
end
keep_doing_more_things
end
end
And the helper method that yields to the block looks like this:
class Foo
def self.some_method(targets, &block)
targets.each do |target|
begin
r = yield(target)
rescue
failed << target
end
end
end
end
The goal is to make the outer do_things method stop immediately when a bad value is found, without putting application-specific logic inside Foo.some_method. What is the correct Ruby approach here, and how do return, break, and exceptions behave in blocks?
Short Answer
By the end of this page, you will understand how control flow works inside Ruby blocks, especially the difference between return, break, and next. You will also see why a return inside a block can exit the outer method, when that is appropriate, and how to design iterator methods so they remain generic and reusable.
Concept
Ruby blocks are not methods. They are chunks of code passed into another method and executed with yield or by calling a block object.
That difference matters because flow-control keywords behave differently inside blocks than inside normal methods.
Key ideas:
returninside a block tries to return from the method where the block was originally defined.breakexits the current iterator or yielding method.nextskips to the next iteration of the block.raisethrows an exception and should be used for actual exceptional conditions, not ordinary loop control unless that design is intentional.
In your example, the block is defined inside Bar#do_things. That means:
return y_is_bad if y.bad?
tries to return from do_things, not from Foo.some_method.
This is one of Ruby's important block behaviors: a block can perform a non-local return.
Why this matters in real programming:
- You often pass blocks to iterator methods like
each,map,find, or custom helper methods.
Mental Model
Think of a Ruby block like a helper standing inside the outer method's room.
returnmeans: leave the whole room now.breakmeans: stop this current task.nextmeans: skip this item and continue with the next one.
So if do_things is the room, and Foo.some_method is just handing items to the helper, then return from inside the block says: "I am done with do_things entirely."
Syntax and Examples
Core flow-control keywords in Ruby blocks
array.each do |item|
next if item < 0 # skip this item
break if item == 5 # stop the loop
puts item
end
nextskips the current iteration.breakstops the loop or iterator.returnexits the surrounding method if used inside a block defined in that method.
Returning from the outer method
class Bar
def do_things(values)
values.each do |value|
return :bad_value if value < 0
puts value
end
:all_good
end
end
bar = Bar.new
p bar.do_things([1, 2, -1, ])
Step by Step Execution
Consider this example:
class Foo
def self.some_method(targets)
targets.each do |target|
yield(target)
end
end
end
class Bar
def do_things(targets)
Foo.some_method(targets) do |x|
y = x * 2
return :bad if y > 5
puts y
end
:finished
end
end
bar = Bar.new
p bar.do_things([1, 2, 3, 4])
Execution trace
bar.do_things([1, 2, 3, 4])starts.Foo.some_method(targets)is called.some_methodbegins iterating over the array.- First item:
x = 1
Real World Use Cases
This kind of control flow appears often in Ruby programs.
Validation pipelines
Stop processing as soon as invalid data is found:
records.each do |record|
return :invalid if record.email.nil?
end
Request handling in web apps
End a controller or service method early when a condition fails:
def process_user(user)
return :not_found unless user
return :inactive if user.inactive?
:ok
end
Import scripts
Abort a larger operation when one item makes the whole batch unusable.
Filtering and scanning
When checking many items, you may want to stop at the first match or failure rather than continue unnecessarily.
Service objects
A method may call a generic iterator helper and use return in the block to exit the service method early without changing the helper's generic design.
Real Codebase Usage
In real Ruby codebases, developers usually choose among a few patterns.
1. Early return from the outer method
Good when the block is part of a larger method and failure should end that method immediately.
def process_items(items)
items.each do |item|
return :failed if item.invalid?
end
:success
end
2. Use predicate methods like any?, find, or detect
Sometimes a built-in enumerable expresses the intent more clearly.
bad_item = items.find(&:invalid?)
return :failed if bad_item
This is often easier to read than manual iteration.
3. Guard clauses
Ruby developers often prefer short early exits:
def do_things(targets)
return :no_targets targets.empty?
.some_method(targets) ||
result = target.do_something
result.bad?
Common Mistakes
Mistake 1: Thinking break returns from the outer method
Broken expectation:
def example
[1, 2, 3].each do |n|
break :stop if n == 2
end
:done
end
p example
# => :done
Why:
breakstopseach- it does not return from
example
If you want to exit example, use return.
Mistake 2: Rescuing everything
Problematic code:
begin
yield(target)
rescue
failed << target
end
Why this is bad:
- It hides real bugs.
- It makes debugging harder.
Comparisons
return vs break vs next in Ruby blocks
| Keyword | What it does | Stops iteration? | Exits outer method? | Typical use |
|---|---|---|---|---|
return | Returns from the method where the block was defined | Yes | Yes | End the whole method early |
break | Exits the current block/iterator | Yes | No | Stop looping |
next | Skips the current iteration | No | No | Ignore one item and continue |
Block vs lambda
Cheat Sheet
Quick rules
- A Ruby block is not a method.
returninside a block returns from the surrounding method where the block was defined.breakexits the iterator or yielding method.nextskips to the next iteration.- Prefer specific
rescueclauses, not barerescue.
Common patterns
# Exit outer method early
items.each do |item|
return :bad if item.bad?
end
# Stop loop only
items.each do |item|
break if item.bad?
end
# Skip one item
items.each do |item|
next if item.nil?
puts item
end
Safer rescue
FAQ
How do I return from the outer method inside a Ruby block?
Use return inside the block. If the block was defined inside a method, Ruby returns from that outer method.
Does break return from the surrounding method in Ruby?
No. break only stops the current iterator or yielding method.
What is the difference between break and return in Ruby blocks?
break stops the loop. return exits the method where the block was defined.
Should I use raise to stop iteration in Ruby?
Usually no, unless the situation is truly exceptional. For normal control flow, prefer return, break, next, or a clearer enumerable method.
Why is a bare rescue dangerous in Ruby?
Because it catches too much and can hide real bugs. Rescue a specific exception class whenever possible.
Is a lambda the same as a block in Ruby?
No. They are related, but return behaves differently. A lambda returns from itself, while a block can return from the outer method.
Mini Project
Description
Build a small Ruby method that scans a list of orders and stops immediately if it finds an invalid order. This demonstrates how a block can trigger an early return from the outer method while a generic helper method stays reusable.
Goal
Create a method that returns :invalid_order as soon as a bad order is found, otherwise returns :processed.
Requirements
- Create a generic helper method that iterates over a collection and yields each item.
- Create an
Orderobject with aninvalid?check. - In the outer processing method, return early when an invalid order is found.
- Return
:processedif all orders are valid.
Keep learning
Related questions
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.
Calling an Overridden Monkey-Patched Method in Ruby
Learn how to call the original method when monkey patching in Ruby, including alias_method patterns, examples, pitfalls, and practical usage.
Convert a Unix Timestamp to Ruby DateTime
Learn how to convert Unix timestamps to Ruby DateTime and Time objects, with examples, differences, pitfalls, and practical Ruby usage.