Question
In Ruby, I know that writing:
some_objects.each(&:foo)
is commonly used as a shorter form of:
some_objects.each { |obj| obj.foo }
My understanding is that &:foo somehow creates a block like { |obj| obj.foo }, converts it to a Proc, and passes it to each.
Why does this work in Ruby? Is &:foo just a special language shortcut, or is there a deeper reason in the language for why it behaves this way?
Short Answer
By the end of this page, you will understand how Ruby's & operator works with blocks, how a Symbol like :foo becomes a callable object through to_proc, and why some_objects.map(&:name) is a real language feature rather than a random special case. You will also see when this shortcut is helpful and when a normal block is clearer.
Concept
In Ruby, the &:method_name pattern is based on two language features working together:
&in a method call means: convert this object into a block.Symbol#to_proclets a symbol such as:footurn into aProc.
So when Ruby sees this:
some_objects.each(&:foo)
it roughly interprets it like this:
some_objects.each(&(:foo.to_proc))
And :foo.to_proc produces a proc that calls foo on whatever object it receives.
Conceptually, it behaves like:
proc { |obj| obj.foo }
That is why it works with iterator methods such as each, map, select, and similar methods that accept blocks.
Why this matters
This feature matters because Ruby treats behavior as data. Blocks, procs, methods, and objects that can be converted into procs all fit into Ruby's flexible style.
The &:symbol form is useful when:
- you want to call the same method on every item in a collection
- the block would otherwise be very short
- readability improves through less repetition
For example:
users.map(&:name)
is a concise way to say:
users.map { |user| user.name }
This is not an isolated exception added only for Symbol. It is part of Ruby's broader rule that &object in a method call tries to call to_proc on that object.
Mental Model
Think of & as a block adapter.
A method like each wants a block. But instead of giving it a normal block directly, you hand Ruby an object.
some_objects.each(&:foo)
Ruby says:
- “I need a block here.”
- “You gave me
:foowith an&.” - “Let me ask
:footo turn itself into a proc by callingto_proc.” - “Now I can use that proc as the block.”
A symbol like :foo is therefore acting like a label for a method name. Ruby converts that label into a callable block that says:
- “When I receive an object, call
fooon it.”
So you can imagine &:foo as a little remote control button labeled foo. Each object in the collection gets the same button pressed on it.
Syntax and Examples
Core syntax
collection.map(&:method_name)
This is shorthand for:
collection.map { |item| item.method_name }
Example 1: Extract names
users = [
OpenStruct.new(name: "Ava"),
OpenStruct.new(name: "Ben"),
OpenStruct.new(name: "Cara")
]
names = users.map(&:name)
puts names.inspect
Output:
["Ava", "Ben", "Cara"]
Explanation:
maploops through each user&:namebecomes a proc- that proc calls
nameon each user mapcollects the returned names into a new array
Example 2: Convert strings to integers
numbers = ["1", "2", "3"]
ints = numbers.map(&:to_i)
puts ints.inspect
Output:
[1, 2, 3]
Example 3: Same result with a normal block
numbers = ["1", "2", "3"]
ints = numbers.map { |n| n.to_i }
puts ints.inspect
This is often easier for beginners to read. The shortcut is nice, but the block form is more explicit.
What & does generally
& is not only for symbols. It can also pass an existing proc as a block:
double = proc { |x| x * 2 }
result = [1, 2, 3].map(&double)
puts result.inspect
Output:
[2, 4, 6]
In both cases, & is about supplying a block.
Step by Step Execution
Consider this code:
words = ["cat", "dog", "bird"]
lengths = words.map(&:length)
puts lengths.inspect
Here is what happens step by step:
wordsis an array containing three strings.mapstarts iterating through each element.- Ruby sees
&:lengthand knowsmapexpects a block. - Ruby calls
to_procon:length. - That creates a proc that behaves roughly like:
proc { |item| item.length }
mapcalls that proc for each item:- for
"cat"→"cat".length→3 - for
"dog"→"dog".length→3 - for
"bird"→"bird".length→4
- for
mapcollects the results into a new array.lengthsbecomes:
[3, 3, 4]
Important detail
This is only “roughly” equivalent to proc { |item| item.length }. The real implementation of Symbol#to_proc has Ruby-specific behavior, but this mental model is correct for normal use.
Real World Use Cases
Common places you will see &:symbol
Transforming arrays
products.map(&:price)
orders.map(&:id)
messages.map(&:strip)
Used when you want one property or one method result from every object.
Cleaning input data
params[:tags].map(&:strip).reject(&:empty?)
Useful for removing extra spaces and blank values.
Working with API or database results
users.map(&:email)
records.map(&:attributes)
Developers often extract fields from collections of model objects.
Type conversion
csv_row.map(&:to_s)
values.map(&:to_i)
Helpful when normalizing incoming data.
Boolean-style filtering
items.select(&:valid?)
This keeps only items for which valid? returns true.
When it fits best
Use &:symbol when the block only calls a single method on each element. If the logic needs conditions, multiple method calls, or extra variables, a normal block is usually clearer.
Real Codebase Usage
In real Ruby projects, &:symbol appears most often in collection pipelines.
Common patterns
Simple mapping
user_names = users.map(&:name)
Validation and filtering
valid_orders = orders.select(&:valid?)
Cleanup chains
tags = raw_tags.map(&:strip).reject(&:empty?).uniq
Guarding readability
Developers often avoid &:symbol if the expression becomes harder to understand.
# Clear
users.map(&:name)
# Often clearer as a block
users.map { |user| user.profile.display_name }
How it relates to other Ruby patterns
- Guard clauses: not directly related, but both aim to keep code concise and readable.
- Validation:
select(&:valid?)is common when filtering objects by a predicate method. - Error handling: if some objects may not respond to the method, developers usually avoid
&:symbolunless they are sure the method exists. - Method pipelines:
map(&:strip).reject(&:empty?)is a common functional style in Ruby.
Team style matters
Many teams use &:symbol only when:
- the method call is obvious
- all objects in the collection support the method
- the shortened syntax improves readability
If not, they prefer the full block form.
Common Mistakes
1. Thinking &:foo is magic syntax only for symbols
It is not a one-off exception. & means “convert this object to a proc for use as a block.” Symbols work because Symbol defines to_proc.
2. Using it when the method needs extra logic
Broken for readability:
users.map(&:name.downcase)
This does not mean “call name.downcase on each user.”
Write this instead:
users.map { |user| user.name.downcase }
3. Using it on objects that do not respond to the method
items = ["a", 1, nil]
items.map(&:upcase)
This will fail because 1 and nil do not have upcase.
Safer alternative:
items.filter_map { |item| item.upcase if item.respond_to?(:upcase) }
4. Assuming it always improves readability
This is valid:
users.map(&:name)
But sometimes the explicit version is clearer:
users.map { |user| user.name }
Especially for beginners or when the collection contents are not obvious.
5. Confusing & in method definitions and method calls
In a method call:
array.map(&:to_s)
& converts an object to a block.
In a method definition:
def run(&block)
block.call
end
&block captures a block as a Proc.
Same symbol, different direction.
6. Forgetting that map returns a new array
names = users.map(&:name)
This does not change users. It creates a new array containing the results.
Comparisons
&:symbol vs explicit block
| Style | Example | Best when | Notes |
|---|---|---|---|
&:symbol | users.map(&:name) | One simple method call | Very concise |
| Explicit block | `users.map { | u | u.name }` |
map(&:foo) vs each(&:foo)
| Method | Purpose | Return value |
|---|---|---|
map(&:foo) | Transform each element into a new value | New array of results |
each(&:foo) | Perform an action for each element | Usually returns the original collection |
&proc vs &:symbol
| Form | Example | Meaning |
|---|---|---|
&proc_object | array.map(&double) | Pass an existing proc as the block |
&:symbol | array.map(&:to_i) | Convert symbol to proc, then use as the block |
When not to use &:symbol
| Situation | Better choice |
|---|---|
| Need multiple method calls | Explicit block |
| Need conditionals | Explicit block |
| Need local variables | Explicit block |
| Simple one-method call | &:symbol is often fine |
Cheat Sheet
Quick reference
Basic form
collection.map(&:method_name)
Equivalent to:
collection.map { |item| item.method_name }
Why it works
&tells Ruby to treat something as a block- Ruby calls
to_procon the object after& Symbol#to_procturns:nameinto a proc that callsname
Common examples
users.map(&:name)
strings.map(&:upcase)
values.map(&:to_i)
orders.select(&:paid?)
Good use cases
- one short method call per item
- readable collection transformations
- simple predicate filtering
Avoid when
- you need chained logic like
user.name.downcase - you need conditionals
- not every object supports the method
Related & usage
Capture a block in a method definition:
def run(&block)
block.call
end
Pass a proc as a block:
double = proc { |x| x * 2 }
[1, 2, 3].map(&double)
Rule of thumb
If the block is just “call one method on each item,” &:symbol is a good option. Otherwise, use a normal block.
FAQ
What does &:name mean in Ruby?
It means Ruby converts the symbol :name into a proc and uses it as the block. In practice, it calls name on each item.
Is &:symbol exactly the same as { |x| x.foo }?
For common usage, yes, that is the right mental model. Internally, Ruby uses Symbol#to_proc to create the proc.
Why does the ampersand work here?
In a method call, & tells Ruby to convert an object into a block by calling to_proc on it.
Is this only for symbols?
No. Any object that implements to_proc can be used with & in a method call.
When should I avoid &:symbol?
Avoid it when the logic is more than one simple method call, or when the shorter syntax makes the code harder to read.
Does each(&:foo) return the results of foo?
Usually no. each typically returns the original collection. If you want collected results, use map.
Can I write users.map(&:name.downcase)?
No. That is not valid for chaining method calls in the shortcut form. Use a normal block instead.
Is &block in a method definition the same thing?
It is related but used differently. In a method definition, &block captures a passed block as a Proc. In a method call, &object converts an object into a block.
Mini Project
Description
Build a small Ruby script that processes a list of users and demonstrates when &:symbol is useful. This project shows how to extract values, filter records, and compare the shortcut with explicit blocks in a realistic collection-processing task.
Goal
Create a script that reads an array of user objects, prints all names, keeps only active users, and formats email addresses in lowercase.
Requirements
- Define a simple
Userclass withname,email, andactiveattributes. - Create an array with at least four user objects.
- Use
map(&:name)to collect user names. - Use a predicate method with
selectto keep only active users. - Use an explicit block for a transformation that needs more than one method call.
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.