How to extend rake tasks with pre and post hooks in Ruby on Rails
Rake tasks are the workhorses of Ruby on Rails applications. From database migrations to asset compilation, they handle crucial operations that keep our applications running smoothly. But sometimes, the default behavior isn't quite enough. What if you need to back up your database before running migrations? Or maybe you want to send a notification after a deployment task completes?
Enter Rake's enhance
method – a powerful but often overlooked feature that lets you extend existing Rake tasks without modifying their original code. In this article, I'll show you how to use enhance
to add pre-script and post-script hooks to any Rake task. Let's dive in!
Understanding the Rake::Task#enhance method
At its core, the enhance
method allows you to modify existing Rake tasks by adding prerequisites or appending code that runs after the task completes. Here's the basic syntax:
Rake::Task["task:name"].enhance(["prerequisite:task"]) do
# Code to run after task:name completes
end
This simple pattern gives you two ways to extend a task:
- Adding prerequisite tasks that run before the main task
- Adding a block of code that runs after the main task
Let's break this down with some practical examples.
Adding pre-execution hooks
Pre-execution hooks are perfect when you need to ensure something happens before a task runs. For example, you might want to back up your database before running migrations. Here's how you could set that up:
# lib/tasks/database_hooks.rake
namespace :backup do
desc "Backup the database before migrations"
task :database => :environment do
puts "🔒 Creating database backup..."
# Your backup logic here
system "pg_dump -Fc #{Rails.application.config.database_configuration[Rails.env]['database']} > #{Rails.root}/db/backups/#{Time.now.strftime('%Y%m%d%H%M%S')}_pre_migration.dump"
puts "✅ Database backup completed!"
end
end
# Now enhance the db:migrate task to run our backup first
Rake::Task["db:migrate"].enhance(["backup:database"])
When you run rake db:migrate
, Rails will first execute backup:database
before performing the actual migration. This ensures you always have a safety net before making database changes.
Adding post-execution hooks
Post-execution hooks run after a task completes, making them perfect for notifications, logging, or cleanup operations. Let's say you want to notify your team when a deployment task finishes:
# lib/tasks/deploy_hooks.rake
namespace :notify do
desc "Send notification after deployment"
task :team => :environment do
puts "📣 Sending deployment notification..."
# Your notification logic here
DeploymentMailer.success_notification(Rails.env).deliver_now
SlackNotifier.new.notify("Deployment to #{Rails.env} completed successfully!")
puts "✅ Team notified of deployment!"
end
end
# Enhance the deploy:finished task with a post-execution hook
Rake::Task["deploy:finished"].enhance do
Rake::Task["notify:team"].invoke
end
In this example, after deploy:finished
completes, our block will run and invoke the notify:team
task.
Combining pre and post hooks
You can use both types of hooks together for more complex workflows:
# lib/tasks/test_hooks.rake
namespace :test do
desc "Setup test environment"
task :setup => :environment do
puts "🛠 Setting up test environment..."
# Setup logic here
end
desc "Clean up after tests"
task :cleanup => :environment do
puts "🧹 Cleaning up test artifacts..."
# Cleanup logic here
end
end
# Enhance the test task with both pre and post hooks
Rake::Task["test"].enhance(["test:setup"]) do
Rake::Task["test:cleanup"].invoke
end
Now when you run rake test
, it will:
- First run
test:setup
(pre-hook) - Then run the original
test
task - Finally run
test:cleanup
(post-hook)
Summary
Rake's enhance
method is a powerful tool for extending existing tasks without modifying their original code. By using pre-execution hooks (prerequisites) and post-execution hooks (blocks), you can create more robust and flexible workflows in your Rails applications. Whether you're adding safety checks before critical operations or notifications after important tasks, this pattern helps you build more resilient systems.
Happy hooking!