Question

Ruby Blocks and yield: A Beginner’s Guide

rubyruby-block

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
Take Quiz

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:

  1. Ruby calls with_discount with 100, so price is 100 inside the method.
  2. The first puts prints Original price: $100.
  3. Ruby reaches yield(price) and runs the supplied block.
  4. The block receives 100 in its own price parameter.
  5. The last expression in the block, price * 0.8, evaluates to 80.0.
  6. yield(price) evaluates to 80.0, which Ruby assigns to final_price.
  7. The second puts prints Final 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, and sort_by take 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; yield inserts 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.”

Take Quiz

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

FeatureWhat it doesTypical use
BlockAn unnamed chunk of code passed to a method`users.each {
yieldRuns the block given to the current methodCalling a customization block once or more
block_given?Checks whether the caller supplied a blockMaking a block optional
&blockCaptures a block as a Proc objectCalling it later with block.call, passing it onward
ProcA reusable object that represents callable codeStoring callbacks or sharing behavior
LambdaA stricter kind of Proc with method-like argument and return behaviorExplicit 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, yield runs 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 with content_for(:sidebar).
Take Quiz

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 ... end or { ... }.
  • yield executes the block passed to the current method.
  • yield(arguments) sends values to block parameters.
  • The value of yield is the block’s return value.
  • Calling yield without a supplied block raises LocalJumpError.
  • 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.

Take Quiz

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

Take Quiz

Keep learning

Related questions

View more