Question
I am trying to understand how blocks and yield work in Ruby.
How do you use yield, and what does it do? I have also seen yield used in Rails applications in ways that seem unusual, especially in layout files. Can you explain the concept and point me toward the right way to understand it?
Short Answer
By the end of this page, you will understand what a Ruby block is, how a method runs a supplied block with yield, how to pass values into and receive values from blocks, and why Rails layouts use yield to insert page-specific content.
Concept
A block is a piece of code that can be passed to a Ruby method for that method to run later. Blocks are commonly written with either { ... } or do ... end.
[1, 2, 3].each do |number|
puts number
end
In this example, each receives the block and runs it once for every array element.
yield is the keyword a method uses to run the block it received.
def greet
puts "Before the block"
yield
puts "After the block"
end
greet do
puts "Hello from the block!"
end
The method does not need to name the block just to execute it. Calling yield transfers control from the method to the block. When the block finishes, execution returns to the line after yield.
This matters because it lets methods provide a reusable structure while callers provide the customizable work. Ruby iterators such as each, resource-management helpers, test frameworks, and Rails layouts all use this idea.
Mental Model
Think of a method as a cooking appliance and a block as the ingredient or instruction supplied by the caller.
The appliance controls the overall process: it starts, performs its built-in work, and finishes. At the point where customization is needed, it says “now do the caller’s instruction”. In Ruby, that instruction is yield.
def prepare_meal
puts "Heat the pan"
yield
puts "Serve the meal"
end
The method provides the fixed steps. The caller decides what happens in the middle:
prepare_meal do
puts "Cook vegetables"
end
Syntax and Examples
A block can use do ... end or braces:
# do ... end is usually easier to read for multi-line blocks
3.times do
puts "Hello"
end
# Braces are often used for short, single-line blocks
3.times { puts "Hello" }
A method runs its supplied block with yield:
def announce
puts "Starting"
yield
puts "Finished"
end
announce do
puts "The block is running."
end
Output:
Starting
The block is running.
Finished
Passing values to a block
Pass values as arguments to yield. The block receives them between | characters.
def describe_user(name, role)
yield(name, role)
end
describe_user("Maya", "admin") do |name, role|
puts "#{name} is an #{role}."
end
Getting a value back from a block
A block returns its final expression, just like a method. yield evaluates to that returned value.
def calculate
result = yield(10, 5)
puts "Result: #{result}"
end
calculate do |first, second|
first + second
end
Output:
Result: 15
Step by Step Execution
Consider this method:
def with_discount(price)
puts "Original price: $#{price}"
final_price = yield(price)
puts "Final price: $#{final_price}"
end
with_discount(100) do |price|
price * 0.8
end
Execution proceeds as follows:
- Ruby calls
with_discountwith100, sopriceis100inside the method. - The first
putsprintsOriginal price: $100. - Ruby reaches
yield(price)and runs the supplied block. - The block receives
100in its ownpriceparameter. - The last expression in the block,
price * 0.8, evaluates to80.0. yield(price)evaluates to80.0, which Ruby assigns tofinal_price.- The second
putsprintsFinal price: $80.0.
The output is:
Original price: $100
Final price: $80.0
Real World Use Cases
Blocks are useful whenever a method should control a process but let callers customize one part of it.
- Iterating over data:
array.each,map,select, andsort_bytake blocks that describe what to do with each value. - Filtering API or database results: select records whose status is active or whose date is recent.
- Timing code: run a block and measure how long it takes.
- Temporary resource handling: open a file, yield it to the caller, then ensure it is closed.
- Configuration DSLs: Rails routes and tests use blocks to group configuration or assertions.
- Rails layouts: a layout provides shared HTML such as the header and navigation;
yieldinserts the current view’s content into that shared structure.
For example, a Rails layout often contains:
<body>
<nav>My App</nav>
<main>
<%= yield %>
</main>
</body>
When Rails renders a page view such as posts/index.html.erb, the view content is inserted where <%= yield %> appears. In ERB, <%= means “evaluate this Ruby expression and print its result into the HTML.”
Real Codebase Usage
In production Ruby code, blocks are commonly used to make repetitive work safe and readable.
Guarding an optional block
Calling yield without a block raises LocalJumpError. If a block is optional, check first:
def log(message)
puts "LOG: #{message}"
yield if block_given?
end
log("User signed in") do
puts "Sending analytics event"
end
Resource cleanup with ensure
A method can open a resource, give it to a block, and clean up even if an error occurs.
def with_file(path)
file = File.open(path, "r")
yield(file)
ensure
file&.close
end
Ruby already provides this pattern through File.open:
File.open("notes.txt", "r") do |file|
puts file.read
end
After the block ends, Ruby closes the file.
Named blocks with &block
Use &block when you need to store, pass, or call the block explicitly instead of immediately yielding to it.
def run_twice(&block)
block.call
block.call
end
run_twice { puts "Running" }
Prefer yield when you only need to execute the given block. It is direct and communicates the intention clearly.
Common Mistakes
Calling yield when no block was given
This raises LocalJumpError:
def welcome
yield
end
welcome
Avoid it by requiring a block in the method’s documentation or checking with block_given?:
def welcome
return "No custom message" unless block_given?
yield
end
Forgetting to pass values to the block
If the block needs a value, provide it through yield:
# Incorrect: the block receives no number
def repeat_number
yield
end
# Correct
def repeat_number(number)
yield(number)
end
Expecting yield to print a value automatically
yield runs the block and returns its result; it does not print it unless you print it.
def get_name
yield
end
name = get_name { "Ava" }
puts name
Confusing yield with the value returned by the whole method
A method returns its final evaluated expression. If code comes after yield, that later code may become the method result.
def example
yield
"method result"
end
puts example { "block result" } # method result
Store or explicitly return the yielded value if that is what you need.
def example
result = yield
result
end
Using <% yield %> instead of <%= yield %> in an ERB Rails layout
<% ... %> executes Ruby but does not output its result. A layout normally needs:
<%= yield %>
so the rendered view content appears in the page.
Comparisons
| Feature | What it does | Typical use |
|---|---|---|
| Block | An unnamed chunk of code passed to a method | `users.each { |
yield | Runs the block given to the current method | Calling a customization block once or more |
block_given? | Checks whether the caller supplied a block | Making a block optional |
&block | Captures a block as a Proc object | Calling it later with block.call, passing it onward |
Proc | A reusable object that represents callable code | Storing callbacks or sharing behavior |
| Lambda | A stricter kind of Proc with method-like argument and return behavior | Explicit callable functions |
yield versus block.call
def using_yield
yield
end
def using_proc(&block)
block.call
end
Both methods can run a caller’s block. Use yield when execution is the only thing you need. Use &block when you need the block as an object—for example, to call it conditionally multiple times or pass it to another method.
Rails yield versus Ruby method yield
They use the same Ruby idea: execute supplied content at a defined location.
- In a normal Ruby method,
yieldruns a Ruby block supplied by the method caller. - In a Rails ERB layout,
<%= yield %>renders the view content supplied to the layout. - Rails can also render named content areas with
yield(:sidebar)together withcontent_for(:sidebar).
Cheat Sheet
# Run a required block
def run_task
yield
end
run_task { puts "Done" }
# Pass arguments into a block
def transform(value)
yield(value)
end
transform(5) { |number| number * 2 } # => 10
# Save the block result
def around
result = yield
puts "Completed"
result
end
# Make a block optional
def optional_work
yield if block_given?
end
# Capture a block as a Proc
def later(&block)
block.call
end
- A block is passed after a method call, usually with
do ... endor{ ... }. yieldexecutes the block passed to the current method.yield(arguments)sends values to block parameters.- The value of
yieldis the block’s return value. - Calling
yieldwithout a supplied block raisesLocalJumpError. - In Rails layouts, use
<%= yield %>to output the rendered view.
FAQ
What is yield in Ruby?
yield runs the block that was supplied when the current method was called. It can also pass arguments into that block and receive the block’s return value.
Does every Ruby method have a block?
No. A caller may provide a block, but it is optional unless the method expects and calls yield. Check with block_given? when the block is optional.
What happens if Ruby calls yield without a block?
Ruby raises LocalJumpError. Avoid this by requiring a block or writing yield if block_given?.
Can a method call yield more than once?
Yes. Each yield runs the same block again.
def twice
yield
yield
end
Can I pass arguments to a Ruby block with yield?
Yes. Write yield(value) in the method and receive it with |value| in the block.
What does <%= yield %> mean in a Rails layout?
It outputs the content of the view being rendered into that location in the layout. The layout supplies shared page structure, while the view supplies page-specific content.
When should I use yield instead of &block?
Use yield when you only need to execute the block. Use &block when you need a Proc object, such as when storing the block, passing it to another method, or calling it with block.call.
Mini Project
Description
Build a small Ruby helper that measures how long a supplied task takes. This demonstrates a common block pattern: the method handles repeated setup and reporting, while the caller supplies the task to perform.
Goal
Create a measure method that runs a block, reports its duration, and returns the block’s result.
Requirements
Requirement 1
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.
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.