Overview
Ruby implements conditional logic through if
, elsif
, and else
statements that evaluate expressions and execute code blocks based on truthiness. Ruby considers all values truthy except false
and nil
. The conditional system supports multiple branching paths, modifier syntax, ternary operators, and case statements for complex decision-making scenarios.
Ruby's conditional statements return values, making them expressions rather than just control flow statements. The last evaluated expression in the executed branch becomes the return value of the entire conditional construct.
# Basic conditional structure
result = if temperature > 30
"hot"
elsif temperature > 20
"warm"
else
"cool"
end
# => "warm" (if temperature is 25)
# Truthiness evaluation
if user && user.active?
process_user(user)
end
# Single-line modifier syntax
return "invalid" if input.nil?
Basic Usage
The if
statement evaluates a condition and executes the associated code block when the condition is truthy. Ruby supports both multiline and modifier forms of conditionals.
# Standard if statement
if user.authenticated?
redirect_to dashboard_path
end
# if/else branching
if file.exists?
content = file.read
else
content = "default content"
end
# Multiple conditions with elsif
if score >= 90
grade = "A"
elsif score >= 80
grade = "B"
elsif score >= 70
grade = "C"
else
grade = "F"
end
The modifier syntax places the condition after the statement, creating more concise code for simple conditionals:
# Modifier if
puts "Processing..." if debug_mode
# Modifier unless (opposite of if)
raise ArgumentError unless params.valid?
# Assignment with modifier
total = calculate_sum if items.any?
Logical operators combine multiple conditions within a single if statement:
# AND operator
if user.admin? && feature_enabled?
show_admin_panel
end
# OR operator
if weekend? || holiday?
office_closed = true
end
# Complex logical expressions
if (user.premium? || user.trial_active?) && !user.suspended?
grant_access
end
Advanced Usage
Ruby conditionals support complex nested structures, pattern matching with case statements, and functional programming patterns through conditional assignment and chaining.
# Nested conditionals with complex logic
def process_payment(amount, user, payment_method)
if amount > 0
if user.verified?
if payment_method.valid?
if payment_method.type == "credit_card"
if payment_method.expires_at > Date.current
charge_credit_card(amount, payment_method)
else
{ error: "Expired card" }
end
elsif payment_method.type == "bank_transfer"
initiate_bank_transfer(amount, payment_method)
else
{ error: "Unsupported payment method" }
end
else
{ error: "Invalid payment method" }
end
else
{ error: "User not verified" }
end
else
{ error: "Invalid amount" }
end
end
Case statements provide cleaner alternatives to long elsif chains:
# Case statement with value matching
def handle_response_code(code)
case code
when 200..299
process_success
when 300..399
handle_redirect
when 400..499
log_client_error
when 500..599
alert_server_error
else
log_unknown_error
end
end
# Case with type matching
def process_data(input)
case input
when String
parse_string(input)
when Array
input.map { |item| process_data(item) }
when Hash
input.transform_values { |value| process_data(value) }
when NilClass
default_value
else
raise TypeError, "Unsupported type: #{input.class}"
end
end
Conditional assignment operators provide concise ways to set values:
# OR-equals assignment (only assigns if left side is falsy)
@user ||= find_user_by_id(session[:user_id])
@cache ||= {}
# Conditional assignment with complex expressions
config[:database_url] ||= begin
if Rails.env.production?
ENV.fetch('DATABASE_URL')
else
"sqlite3:#{Rails.root}/db/development.sqlite3"
end
end
# Ternary operator for inline conditionals
status = user.active? ? "online" : "offline"
message = errors.any? ? "Please fix errors" : "Form submitted successfully"
Common Pitfalls
Ruby's truthiness rules and conditional behavior can lead to unexpected results when developers assume behavior from other languages or misunderstand Ruby's evaluation patterns.
Truthiness Confusion: Only false
and nil
are falsy in Ruby, unlike languages where empty strings, zero, or empty arrays are falsy:
# Common mistake - these are all truthy in Ruby
if ""
puts "Empty string is truthy in Ruby" # This executes
end
if 0
puts "Zero is truthy in Ruby" # This executes
end
if []
puts "Empty array is truthy in Ruby" # This executes
end
# Correct way to check for empty values
if string && !string.empty?
process_string(string)
end
if array && array.any?
process_array(array)
end
Assignment vs. Comparison: Single =
performs assignment and returns the assigned value, which can lead to bugs when ==
was intended:
# Bug - assignment instead of comparison
if user = find_admin_user # Always truthy if find_admin_user returns anything
grant_admin_access
end
# Correct comparison
if user == find_admin_user
grant_admin_access
end
# Intentional assignment with explicit truthiness check
if (user = find_admin_user) && user.active?
grant_admin_access
end
Case Statement Fallthrough: Ruby case statements don't fall through like switch statements in other languages, but multiple values can match a single when clause:
# Each when clause is independent - no fallthrough
case status
when "pending"
queue_for_processing
when "approved"
send_approval_email
# Execution stops here, doesn't continue to next when
when "rejected"
send_rejection_email
end
# Multiple values in single when clause
case day_of_week
when "saturday", "sunday"
weekend_mode = true
when "monday", "tuesday", "wednesday", "thursday", "friday"
weekend_mode = false
end
Nested Conditional Complexity: Deep nesting creates maintenance issues and can be refactored using guard clauses:
# Problematic deep nesting
def process_order(order)
if order
if order.valid?
if order.items.any?
if order.user.verified?
if order.payment_method.present?
process_payment(order)
else
{ error: "No payment method" }
end
else
{ error: "User not verified" }
end
else
{ error: "No items in order" }
end
else
{ error: "Invalid order" }
end
else
{ error: "Order not found" }
end
end
# Refactored with guard clauses
def process_order(order)
return { error: "Order not found" } unless order
return { error: "Invalid order" } unless order.valid?
return { error: "No items in order" } unless order.items.any?
return { error: "User not verified" } unless order.user.verified?
return { error: "No payment method" } unless order.payment_method.present?
process_payment(order)
end
Reference
Conditional Statement Syntax
Construct | Syntax | Returns | Description |
---|---|---|---|
if |
if condition; code; end |
Last evaluated expression | Executes code when condition is truthy |
if/else |
if condition; code1; else; code2; end |
Last evaluated expression from executed branch | Executes code1 or code2 based on condition |
if/elsif/else |
if cond1; code1; elsif cond2; code2; else; code3; end |
Last evaluated expression from executed branch | Multiple conditional branches |
unless |
unless condition; code; end |
Last evaluated expression | Executes code when condition is falsy |
case/when |
case value; when match; code; end |
Last evaluated expression from matched branch | Pattern matching against value |
Modifier Forms
Modifier | Syntax | Description |
---|---|---|
if |
statement if condition |
Executes statement when condition is truthy |
unless |
statement unless condition |
Executes statement when condition is falsy |
Logical Operators
Operator | Name | Precedence | Short-circuit | Description |
---|---|---|---|---|
&& |
AND | High | Yes | Returns first falsy value or last value |
|| |
OR | High | Yes | Returns first truthy value or last value |
and |
AND | Low | Yes | Same as && but lower precedence |
or |
OR | Low | Yes | Same as || but lower precedence |
! |
NOT | Highest | No | Returns opposite truthiness |
not |
NOT | Low | No | Same as ! but lower precedence |
Truthiness Values
Value | Truthiness | Notes |
---|---|---|
true |
Truthy | Boolean true |
false |
Falsy | Boolean false |
nil |
Falsy | Ruby's null value |
0 |
Truthy | Unlike many languages |
"" |
Truthy | Empty string is truthy |
[] |
Truthy | Empty array is truthy |
{} |
Truthy | Empty hash is truthy |
All other objects | Truthy | Including custom objects |
Assignment Operators
Operator | Equivalent | Description |
---|---|---|
||= |
x = x || y |
Assigns only if left side is falsy |
&&= |
x = x && y |
Assigns only if left side is truthy |
+= |
x = x + y |
Addition assignment |
-= |
x = x - y |
Subtraction assignment |
Case Statement Patterns
Pattern | Example | Description |
---|---|---|
Value equality | when 1, 2, 3 |
Matches specific values |
Range matching | when 1..10 |
Matches values in range |
Class matching | when String |
Matches object type |
Regex matching | when /pattern/ |
Matches against regular expression |
Proc matching | when proc |
Calls proc with case value |