Ruby Logo

Rescue-modifiers

Learn about rescue-modifiers in Ruby programming.

Home Ruby Rescue-modifiers

Ruby Rescue Modifiers Mastery

Master Ruby's rescue modifiers for elegant inline exception handling. Learn how to write concise, readable code that gracefully handles errors without verbose begin/rescue blocks.

What are Rescue Modifiers?

Rescue Modifiers: A concise way to handle exceptions inline using the `rescue` keyword as a statement modifier. They allow you to provide fallback values or alternative actions when operations fail, making your code more readable and defensive.

Real-World Analogy

Think of rescue modifiers like safety nets: Just as a trapeze artist has a safety net to catch them if they fall, rescue modifiers catch your code when operations fail and provide a safe fallback. It's like saying "try this, but if it fails, do this instead."

Basic Rescue Modifiers

Basic Syntax: Use `expression rescue fallback_value` to provide a default value when an expression raises an exception.

Simple Fallback Values

# Basic rescue modifier with fallback values
result = risky_operation rescue "default_value"
number = Integer("abc") rescue 0
user_name = get_user_name rescue "Anonymous"

# Practical examples
config_value = ENV["API_KEY"] rescue "default_key"
port = Integer(ENV["PORT"]) rescue 3000
timeout = Float(params[:timeout]) rescue 30.0

# File operations
content = File.read("config.txt") rescue ""
data = JSON.parse(response_body) rescue {}
count = File.readlines("data.txt").size rescue 0

Method Calls with Rescue

# Method calls with rescue modifiers
user = User.find(params[:id]) rescue nil
email = user.email.downcase rescue ""
timestamp = Time.parse(date_string) rescue Time.now

# Chained method calls
title = article.title.strip.downcase rescue "untitled"
price = product.price.to_f.round(2) rescue 0.0
tags = post.tags.map(&:name).join(", ") rescue "No tags"

# API calls with fallbacks
weather = fetch_weather_data(city) rescue { temp: "N/A", condition: "Unknown" }
exchange_rate = get_exchange_rate("USD", "EUR") rescue 1.0

Rescue with Assignment Patterns

Advanced Assignment: Combine rescue modifiers with various assignment operators and patterns to create robust, defensive code that handles errors gracefully while maintaining readability.

Conditional Assignment (||=)

# Combining rescue with ||= for memoization
@cached_data ||= fetch_expensive_data rescue []
@user_preferences ||= load_user_preferences rescue default_preferences
@config ||= YAML.load_file("config.yml") rescue {}

# Instance variable initialization with fallbacks
def
user_settings
@user_settings ||= UserSettings.find(user_id) rescue UserSettings.new
end

def
cached_weather
@cached_weather ||= WeatherAPI.current_weather rescue { temp: "N/A" }
end

Multiple Assignment with Rescue

# Multiple assignment with rescue
lat, lng = parse_coordinates(address) rescue [0.0, 0.0]
name, email, age = parse_user_data(csv_line) rescue ["Unknown", "", 0]
width, height = get_image_dimensions(file) rescue [100, 100]

# Hash assignment with rescue
options = {
timeout: Integer(params[:timeout]) rescue 30,
max_retries: Integer(params[:retries]) rescue 3,
debug: params[:debug] == "true" rescue false
}

# Array assignment with rescue
users = [
User.find(1) rescue nil,
User.find(2) rescue nil,
User.find(3) rescue nil
].compact # Remove nil values

Advanced Rescue Patterns

Advanced Patterns: Combine rescue modifiers with other Ruby features like blocks, method chaining, and conditionals for powerful error-handling patterns.

Rescue in Blocks and Iterators

# Rescue in map operations
numbers = ["1", "2", "abc", "4", "xyz"]
integers = numbers.map { |n| Integer(n) rescue nil }.compact
# => [1, 2, 4]

# Rescue in select operations
valid_emails = email_list.select { |email| validate_email(email) rescue false }
accessible_files = file_paths.select { |path| File.readable?(path) rescue false }

# Rescue in each operations
urls.each do |url|
response = fetch_url(url) rescue nil
process_response(response) if response
end

# Rescue with reduce/inject
total_size = files.reduce(0) do |sum, file|
sum + (File.size(file) rescue 0)
end

Chained Operations with Rescue

# Method chaining with rescue at strategic points
result = data
.fetch("user", {}) rescue {}
.fetch("profile", {}) rescue {}
.fetch("settings", {}) rescue {}

# Safe navigation with rescue
user_name = user&.profile&.name rescue "Anonymous"
avatar_url = user&.profile&.avatar&.url rescue "/default_avatar.png"

# Complex chaining with multiple rescue points
processed_data = raw_data
.split("\n") rescue []
.map { |line| JSON.parse(line) rescue nil }
.compact
.select { |item| item["active"] rescue false }
.map { |item| transform_item(item) rescue nil }
.compact

Conditional Rescue Patterns

# Rescue with ternary operators
result = condition ? risky_operation rescue "default" : safe_operation
value = user.premium? ? expensive_calculation rescue 0 : basic_calculation

# Rescue in conditionals
if
(user_input = get_user_input rescue nil)
process_input(user_input)
else
handle_no_input
end

# Rescue with logical operators
success = (save_data rescue false) && (send_notification rescue false)
fallback = primary_source rescue secondary_source rescue "default"

Real-World Examples

Configuration and Environment

# Environment configuration with fallbacks
class
AppConfig
DATABASE_URL = ENV["DATABASE_URL"] rescue "sqlite3:///tmp/default.db"
PORT = Integer(ENV["PORT"]) rescue 3000
MAX_CONNECTIONS = Integer(ENV["MAX_CONNECTIONS"]) rescue 10
DEBUG_MODE = ENV["DEBUG"] == "true" rescue false
LOG_LEVEL = ENV["LOG_LEVEL"]&.upcase rescue "INFO"

# Complex configuration loading
def
self
.
load_config
config_file = ENV["CONFIG_FILE"] || "config.yml"
YAML.load_file(config_file) rescue default_config
end

def
self
.
default_config
{
"database" => { "adapter" => "sqlite3", "database" => "db/default.sqlite3" },
"cache" => { "type" => "memory", "size" => 100 },
"features" => { "analytics" => false, "notifications" => true }
}
end
end

Data Processing and APIs

# Data processing with rescue modifiers
class
DataProcessor
def
process_csv_row
(row)
{
id: Integer(row[0]) rescue nil,
name: row[1]&.strip rescue "Unknown",
email: row[2]&.downcase&.strip rescue "",
age: Integer(row[3]) rescue 0,
salary: Float(row[4]) rescue 0.0,
active: row[5] == "true" rescue false,
created_at: Date.parse(row[6]) rescue Date.today
}
end

def
safe_api_call
(endpoint, params = {})
response = HTTP.get(endpoint, params: params) rescue nil
json_data = JSON.parse(response.body) rescue {} if response
json_data || { error: "API call failed", data: [] }
end

def
extract_metrics
(data)
{
total_users: data.dig("stats", "users", "total") rescue 0,
active_sessions: data.dig("realtime", "sessions") rescue 0,
conversion_rate: Float(data.dig("conversion", "rate")) rescue 0.0,
last_updated: Time.parse(data.dig("meta", "updated_at")) rescue Time.now
}
end
end

User Interface and Web Applications

# Web application helpers with rescue modifiers
class
ApplicationHelper
def
user_avatar
(user)
user&.avatar&.url rescue "/assets/default_avatar.png"
end

def
format_currency
(amount, currency = "USD")
Money.new(amount * 100, currency).format rescue "$0.00"
end

def
safe_truncate
(text, length = 100)
text&.truncate(length) rescue ""
end

def
parse_search_params
(params)
{
query: params[:q]&.strip rescue "",
page: Integer(params[:page]) rescue 1,
per_page: Integer(params[:per_page]) rescue 25,
sort_by: params[:sort_by]&.to_sym rescue :created_at,
order: params[:order]&.downcase&.to_sym rescue :desc
}
end
end

Interactive Practice: Rescue Modifiers

Practice Time: Try these rescue modifier examples and experiment with your own patterns. Understanding these techniques will make your Ruby code more resilient and readable.

Interactive Code Runner

Ruby Code Editor
Output will appear here when you run the code...

Best Practices & Guidelines

✅ Best Practices

  • Use for simple fallbacks: Rescue modifiers are perfect for providing default values
  • Keep fallbacks simple: Avoid complex expressions in rescue clauses
  • Use specific exceptions: When possible, catch specific exception types
  • Consider readability: Use rescue modifiers when they make code clearer
  • Combine with nil safety: Use with safe navigation operator (&.)
  • Memoization pattern: Great for caching expensive operations

❌ Common Pitfalls

  • Hiding important errors: Don't suppress exceptions that need attention
  • Overusing rescue modifiers: Complex error handling needs begin/rescue
  • Silent failures: Provide meaningful fallback values, not just nil
  • Performance issues: Don't use rescue in tight loops for control flow
  • Debugging difficulties: Log or handle important exceptions properly
  • Generic rescue: Avoid catching all exceptions without specificity

When to Use vs. begin/rescue

Use Rescue Modifiers For:
  • Simple fallback values
  • Configuration loading
  • Data type conversions
  • Memoization patterns
  • Optional operations
Use begin/rescue For:
  • Complex error handling
  • Multiple exception types
  • Cleanup with ensure
  • Error logging/reporting
  • Recovery strategies

Rescue Modifiers Mastery Summary

You've Mastered Ruby Rescue Modifiers!

Inline Error Handling

expression rescue fallback

Assignment Patterns

||= with rescue for memoization

Defensive Programming

Graceful fallbacks and safe operations

Rescue modifiers are a powerful tool for writing clean, defensive Ruby code. Use them wisely to provide graceful fallbacks while keeping your code readable and maintainable. Remember: use rescue modifiers for simple cases, and begin/rescue blocks for complex error handling.

Quick Navigation

Related Topics

Video Tutorial

Watch and learn rescue-modifiers

Pro Tip: After reading through the content above, watch this video to reinforce your understanding and see the concepts in action!