Question
I found the following Ruby code in a RailsCast and want to understand what this part means: map(&:name).
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
What does (&:name) do when used with map in Ruby?
Short Answer
By the end of this page, you will understand why map(&:name) is a short Ruby way to call the name method on every item in a collection. You will also learn how the & operator and symbols work together, how this compares to a normal block, and when this shorthand is useful in real Ruby and Rails code.
Concept
In Ruby, map loops through a collection and returns a new array containing the result of running something on each element.
For example:
[1, 2, 3].map { |n| n * 2 }
# => [2, 4, 6]
When you write:
tags.map(&:name)
Ruby is using a shorthand for a very common pattern:
tags.map { |tag| tag.name }
What the pieces mean
:nameis a symbol representing the method namename&tells Ruby to convert that symbol into something usable as a blockmapthen calls that method on each element
So if tags is a collection of tag objects, map(&:name) means:
- take each
tag - call
tag.name - collect the results into a new array
Why this matters
This syntax appears often in Ruby and Rails because it makes code shorter and easier to scan when you just want to call a single method on every item in a collection.
In your example:
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
the code:
- gets all
tags - extracts each tag's
name - joins those names with spaces
If the tag names were "ruby", "rails", and "api", the result would be:
"ruby rails api"
Under the hood
Ruby supports this because Symbol can be converted into a callable object using to_proc.
So this:
&:name
is roughly like:
{ |object| object.name }
You do not usually need to call to_proc yourself, but it helps explain why the syntax works.
Mental Model
Think of map as a worker on an assembly line.
- The collection is a line of items moving past
mapapplies the same action to each item&:nameis like giving the worker a small instruction card that says: for each item, ask for itsname
So instead of saying:
map { |item| item.name }
you hand Ruby a shortcut card:
map(&:name)
Same job, shorter instruction.
Syntax and Examples
Basic 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: "Liam"),
OpenStruct.new(name: "Noah")
]
users.map(&:name)
# => ["Ava", "Liam", "Noah"]
This calls name on each user object.
Example 2: Convert strings to uppercase
words = ["ruby", "rails", "api"]
words.map(&:upcase)
# => ["RUBY", "RAILS", "API"]
This calls upcase on each string.
Example 3: Compare with block syntax
tags.map(&:name)
is equivalent to:
tags.map { |tag| tag.name }
In your Rails example
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
Explanation:
tags.map(&:name)returns an array of names.join(' ')combines them into one string separated by spaces@tag_names || ...returns@tag_namesif it already exists, otherwise it builds the string fromtags
Example:
tags.map(&:name)
# => ["ruby", "rails", "testing"]
tags.map(&:name).join(' ')
# => "ruby rails testing"
Step by Step Execution
Consider this code:
words = ["ruby", "rails", "api"]
result = words.map(&:upcase)
Here is what happens step by step:
-
wordsis an array with three strings:"ruby""rails""api"
-
mapstarts looping through the array. -
&:upcasetells Ruby: for each element, call theupcasemethod. -
Ruby processes each item:
"ruby".upcase→"RUBY""rails".upcase→"RAILS""api".upcase→"API"
-
mapcollects the results into a new array. -
resultbecomes:
["RUBY", "RAILS", "API"]
Now trace your original example:
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
If @tag_names is nil and tags contains tag objects with names "ruby" and "rails", then:
@tag_namesis checked- because it is
nil, Ruby evaluates the right side of|| tags.map(&:name)becomestags.map { |tag| tag.name }- Ruby builds
["ruby", "rails"] .join(' ')turns that into"ruby rails"- the method returns
"ruby rails"
Real World Use Cases
map(&:method_name) is common when you want one value from each object in a collection.
Common practical uses
-
Rails views: get names or titles for display
@posts.map(&:title) -
Building API responses: extract IDs or fields
users.map(&:id) -
Data cleanup: transform strings
emails.map(&:downcase) -
Admin dashboards: list labels from objects
categories.map(&:name) -
Form helpers: prepare selected values
roles.map(&:name).join(", ")
Why developers like it
- short and readable for simple method calls
- avoids unnecessary block variables
- works well in chains with
map,select, andjoin
Real Codebase Usage
In real Ruby and Rails projects, this shorthand is often used when the block only calls one method with no extra logic.
Typical patterns
Extracting attributes
user_ids = users.map(&:id)
post_titles = posts.map(&:title)
Preparing display strings
tag_list = tags.map(&:name).join(", ")
Working with associations in Rails
@article.comments.map(&:body)
@order.line_items.map(&:price)
Combining with other enumerable methods
users.select(&:active?).map(&:email)
This means:
- keep only active users
- get each user's email
When developers avoid it
If the logic is more than a simple method call, a normal block is usually clearer:
users.map { |user| "#{user.first_name} #{user.last_name}" }
That is better than forcing shorthand where it does not fit.
Readability guideline
Use &:method_name when:
- you are calling exactly one method
- the intent is obvious
- the shorter form improves readability
Use a block when:
- you need multiple operations
- you need conditions
- you need arguments
- the shorthand would hide what the code is doing
Common Mistakes
1. Thinking &:name is special syntax only for map
It is not limited to map. It can be used with other methods that accept a block, such as select, reject, and any?.
users.select(&:active?)
2. Using it when the method needs arguments
This does not work for methods that require extra arguments in this form.
Broken example:
words.map(&:gsub)
Why it fails:
gsubneeds arguments&:gsubonly says "callgsub"- it does not provide the required parameters
Use a block instead:
words.map { |word| word.gsub("a", "@") }
3. Using it when the method may not exist
Broken example:
items.map(&:name)
If some items do not respond to name, Ruby raises an error.
Avoid this by ensuring all objects support the method, or use safer logic.
4. Assuming it is always more readable
Sometimes the long form is clearer:
orders.map { |order| order.total_price.round(2) }
Trying to force shorthand here would not help.
5. Confusing symbols with strings
: creates a symbol, not a string.
:name # symbol
"name" # string
&:name works with a symbol because Ruby can convert it to a proc.
6. Forgetting that map returns a new array
map does not change the original collection unless you use map!.
names = ["ruby", "rails"]
upper = names.map(&:upcase)
# names is still ["ruby", "rails"]
# upper is ["RUBY", "RAILS"]
Comparisons
map(&:name) vs block syntax
| Style | Example | Best for |
|---|---|---|
| Shorthand | tags.map(&:name) | Simple single method calls |
| Block | `tags.map { | tag |
| Block with logic | `tags.map { | tag |
map vs each
| Method | Returns | Use when |
|---|---|---|
map | A new transformed array | You want changed values |
each | The original collection | You want side effects, like printing or saving |
Example:
names = users.map(&:name)
users.each { |user| puts user.name }
map(&:name) vs pluck(:name) in Rails
| Approach | Works on | Notes |
|---|---|---|
map(&:name) | Ruby objects already loaded in memory | Calls name on each object |
pluck(:name) | ActiveRecord query | Fetches only that column from the database |
Example:
User.all.map(&:name)
User.pluck(:name)
In Rails, pluck can be more efficient when you only need database column values.
&:method vs explicit proc
| Style | Example | Meaning |
|---|---|---|
| Symbol shorthand | items.map(&:name) | Convert symbol to proc automatically |
| Explicit proc | items.map(&:method(:name)) | Different and less common here |
| Normal block | `items.map { | i |
Cheat Sheet
Quick reference
Basic form
collection.map(&:method_name)
Equivalent to:
collection.map { |item| item.method_name }
Common examples
users.map(&:name)
posts.map(&:title)
words.map(&:upcase)
users.select(&:active?)
What & does
- converts an object into a block if possible
- with symbols, Ruby uses
to_proc
What :name is
- a symbol representing the method name
name
Good use cases
- calling one method on each element
- short, clear collection transformations
Avoid when
- the method needs arguments
- you need multiple steps
- the shorthand hurts readability
Related equivalent
items.map(&:name)
items.map { |item| item.name }
Important note
map returns a new array. It does not modify the original collection unless you use map!.
FAQ
What does map(&:name) mean in Ruby?
It means: loop through the collection, call name on each item, and return the results in a new array.
Is map(&:name) the same as map { |x| x.name }?
Yes. For this case, they are equivalent.
What does the & do in &:name?
It tells Ruby to convert the symbol into a block-like callable object.
Why is a symbol used instead of a string?
Ruby supports converting symbols like :name into procs for this shorthand. Strings do not work the same way here.
Can I use &:name with methods other than map?
Yes. Any method that accepts a block may be able to use this style, such as select, reject, or any?.
Does map(&:name) work if the method takes arguments?
Usually no. If arguments are needed, use a normal block.
Is map(&:name) always better than a block?
No. It is best for simple single-method calls. A regular block is often clearer when logic is more complex.
In Rails, should I use map(&:name) or pluck(:name)?
If records are already loaded, map(&:name) is fine. If you only need a database column, pluck(:name) is often more efficient.
Mini Project
Description
Build a small Ruby script that works with a list of objects and uses map(&:method_name) to extract data. This helps you practice the shorthand in a realistic way, similar to how Rails apps collect names, titles, or IDs from model objects.
Goal
Create a script that stores several book objects, extracts their titles with map(&:title), and prints them as a single formatted string.
Requirements
- Define a
Bookclass with atitleattribute. - Create at least three
Bookobjects. - Store the books in an array.
- Use
map(&:title)to extract all titles. - Join the titles into one string and print the result.
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.