Enumerables and Iterators
The Enumerable module is one of Ruby's most powerful features. It provides a set of methods for traversing, searching, and manipulating collections. You'll use these constantly in Rails!
The Each Method
The foundation of iteration in Ruby:
ruby
1# Array iteration
2fruits = ["apple", "banana", "cherry"]
3
4fruits.each do |fruit|
5 puts "I like #{fruit}"
6end
7
8# With index
9fruits.each_with_index do |fruit, index|
10 puts "#{index + 1}. #{fruit}"
11end
12
13# Hash iteration
14user = { name: "John", age: 30, city: "NYC" }
15
16user.each do |key, value|
17 puts "#{key}: #{value}"
18end
19
20# Range iteration
21(1..5).each { |n| puts n }Map/Collect - Transform Elements
Create a new array by transforming each element:
ruby
1numbers = [1, 2, 3, 4, 5]
2
3# Double each number
4doubled = numbers.map { |n| n * 2 }
5# => [2, 4, 6, 8, 10]
6
7# Get user names from objects
8users = [
9 { name: "John", age: 30 },
10 { name: "Jane", age: 25 }
11]
12
13names = users.map { |user| user[:name] }
14# => ["John", "Jane"]
15
16# Shorthand for simple method calls
17words = ["hello", "world"]
18words.map(&:upcase)
19# => ["HELLO", "WORLD"]
20
21# In Rails, you'll often see:
22@users.map(&:email) # Get all user emailsSelect/Find_all - Filter Elements
Get elements that match a condition:
ruby
1numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2
3# Get even numbers
4evens = numbers.select { |n| n.even? }
5# => [2, 4, 6, 8, 10]
6
7# Get numbers greater than 5
8large = numbers.select { |n| n > 5 }
9# => [6, 7, 8, 9, 10]
10
11# Filter users by age
12users = [
13 { name: "John", age: 30 },
14 { name: "Jane", age: 17 },
15 { name: "Bob", age: 25 }
16]
17
18adults = users.select { |user| user[:age] >= 18 }
19# => [{ name: "John", age: 30 }, { name: "Bob", age: 25 }]Reject - Exclude Elements
The opposite of select:
ruby
1numbers = [1, 2, 3, 4, 5]
2
3# Reject even numbers (keep odd)
4odds = numbers.reject { |n| n.even? }
5# => [1, 3, 5]
6
7# Reject inactive users
8users = users.reject { |user| user[:status] == "inactive" }Find/Detect - Find First Match
Get the first element that matches:
ruby
1numbers = [1, 2, 3, 4, 5]
2
3# Find first even number
4first_even = numbers.find { |n| n.even? }
5# => 2
6
7# Find user by name
8users = [
9 { name: "John", age: 30 },
10 { name: "Jane", age: 25 }
11]
12
13john = users.find { |user| user[:name] == "John" }
14# => { name: "John", age: 30 }
15
16# Returns nil if not found
17missing = numbers.find { |n| n > 100 }
18# => nilReduce/Inject - Accumulate Values
Combine all elements into a single value:
ruby
1numbers = [1, 2, 3, 4, 5]
2
3# Sum all numbers
4sum = numbers.reduce(0) { |total, n| total + n }
5# => 15
6
7# Shorthand
8sum = numbers.reduce(0, :+)
9# => 15
10
11# Without initial value (uses first element)
12sum = numbers.reduce(:+)
13# => 15
14
15# Multiply all numbers
16product = numbers.reduce(1, :*)
17# => 120
18
19# Build a hash
20words = ["apple", "banana", "cherry"]
21word_lengths = words.reduce({}) do |hash, word|
22 hash[word] = word.length
23 hash
24end
25# => { "apple" => 5, "banana" => 6, "cherry" => 6 }
26
27# Flatten nested arrays
28nested = [[1, 2], [3, 4], [5, 6]]
29flat = nested.reduce([], :+)
30# => [1, 2, 3, 4, 5, 6]All?, Any?, None?, One?
Check conditions across collections:
ruby
1numbers = [2, 4, 6, 8, 10]
2
3# Are all numbers even?
4numbers.all?(&:even?) # => true
5
6# Is any number greater than 5?
7numbers.any? { |n| n > 5 } # => true
8
9# Are none of the numbers negative?
10numbers.none?(&:negative?) # => true
11
12# Is exactly one number equal to 4?
13numbers.one? { |n| n == 4 } # => trueCount, Size, Length
Get collection size or count matching elements:
ruby
1numbers = [1, 2, 3, 4, 5, 2, 2]
2
3numbers.length # => 7
4numbers.size # => 7 (alias)
5numbers.count # => 7
6
7# Count specific value
8numbers.count(2) # => 3
9
10# Count with condition
11numbers.count(&:even?) # => 4Sort and Sort_by
Order elements:
ruby
1numbers = [3, 1, 4, 1, 5, 9, 2, 6]
2
3numbers.sort # => [1, 1, 2, 3, 4, 5, 6, 9]
4numbers.sort.reverse # => [9, 6, 5, 4, 3, 2, 1, 1]
5
6# Custom sort
7words = ["banana", "apple", "cherry"]
8words.sort # => ["apple", "banana", "cherry"]
9
10# Sort by length
11words.sort_by(&:length)
12# => ["apple", "cherry", "banana"]
13
14# Sort users by age
15users = [
16 { name: "John", age: 30 },
17 { name: "Jane", age: 25 },
18 { name: "Bob", age: 35 }
19]
20
21users.sort_by { |user| user[:age] }
22# => [Jane, John, Bob]
23
24# Descending order
25users.sort_by { |user| -user[:age] }
26# => [Bob, John, Jane]Group_by - Group Elements
Create a hash of grouped elements:
ruby
1numbers = [1, 2, 3, 4, 5, 6]
2
3# Group by even/odd
4grouped = numbers.group_by(&:even?)
5# => { false => [1, 3, 5], true => [2, 4, 6] }
6
7# Group users by role
8users = [
9 { name: "John", role: "admin" },
10 { name: "Jane", role: "user" },
11 { name: "Bob", role: "admin" }
12]
13
14by_role = users.group_by { |user| user[:role] }
15# => { "admin" => [...], "user" => [...] }Partition - Split into Two
Divide elements based on condition:
ruby
1numbers = [1, 2, 3, 4, 5, 6]
2
3evens, odds = numbers.partition(&:even?)
4# evens => [2, 4, 6]
5# odds => [1, 3, 5]First, Last, Take, Drop
Access specific elements:
ruby
1numbers = [1, 2, 3, 4, 5]
2
3numbers.first # => 1
4numbers.first(2) # => [1, 2]
5numbers.last # => 5
6numbers.last(2) # => [4, 5]
7
8numbers.take(3) # => [1, 2, 3]
9numbers.drop(2) # => [3, 4, 5]Compact - Remove Nils
ruby
1array = [1, nil, 2, nil, 3]
2
3array.compact # => [1, 2, 3]Flatten - Flatten Nested Arrays
ruby
1nested = [[1, 2], [3, [4, 5]]]
2
3nested.flatten # => [1, 2, 3, 4, 5]
4nested.flatten(1) # => [1, 2, 3, [4, 5]] (one level)Uniq - Remove Duplicates
ruby
1numbers = [1, 2, 2, 3, 3, 3]
2
3numbers.uniq # => [1, 2, 3]
4
5# Unique by attribute
6users.uniq { |user| user[:email] }Chaining Methods
You can chain enumerable methods:
ruby
1numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2
3result = numbers
4 .select(&:even?) # Get even numbers
5 .map { |n| n * 2 } # Double them
6 .take(3) # Take first 3
7# => [4, 8, 12]
8
9# In Rails
10@users
11 .where(active: true)
12 .order(:name)
13 .map(&:email)Mastering enumerables will make you incredibly productive in Ruby and Rails!
