Rake can be used to run tasks in Ruby. Rake is short for "Ruby Make" and is a tool that helps automate steps related to building an environment or deploying applications.
If you're first introduced to Rake through Rails, then it's easy to get started. You can just start putting .*rake
files into the lib/tasks
folder. But as you work more with tasks, you might start to ask questions like:
lib/tasks
folder?*.rake
files clobbering each other?Here's a quick run-through of how to make simple Rake tasks and how they are incorporated in Rails.
Say that we have a Ruby project and there's a task that we want to perform regularly. Let's say we just need it to print this simple message:
puts 'Performing task.'
We can turn this into a Rake task if we install the rake
gem and then create a Rakefile with the following contents:
# Rakefile
desc 'This task will print some output'
task :my_task do
puts 'Performing task.'
end
This command will show the tasks that are available to run:
rake --tasks
And this will run our new task:
rake my_task
Tasks can also have prerequisites, which are other tasks that must run first. So if I update the Rakefile to look like:
# Rakefile
task :prereq do
puts 'Performing prerequisite.'
end
desc 'This task will print some output'
task my_task: :prereq do
puts 'Performing task.'
end
Things to note:
prereq
task won't show in the rake --tasks
list because I didn't give it a description.prereq
task will run first whenever rake my_task
is called.So now calling rake my_task
will result in this output:
Performing prerequisite.
Performing task.
You can also give tasks a namespace to group related tasks together. For example:
namespace :my_namespace do
desc 'This task will print some output'
task :my_task do
puts 'Performing task.'
end
end
And then this task would be invoked with:
rake my_namespace:my_task
For Rake tasks in Rails, rather than register a task in the Rakefile
, we can create *.rake
files. We could define a simple task as:
# lib/tasks/my_task.rake
desc 'This task will print some output'
task :my_task do
puts 'Performing task.'
end
If your task will need to interact with your app code you'll also need to include the special :environment
prerequisite:
# lib/tasks/my_task.rake
desc 'This task will print some output'
task my_task: :environment do
puts 'Performing task.'
end
How does Rake know to look for tasks in the lib/tasks
folder? When you create a new app, Rails will use this template to create a Rakefile
with these contents:
# Rakefile
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require_relative "config/application"
Rails.application.load_tasks
The first line to require config/application
loads all Rails modules (ActiveRecord, ActiveSupport, etc.) but it doesn't load your app code.
The second line to call Rails.application.load_tasks
requires "rake"
and loads all the files in the lib/tasks
folder. The files are loaded within a context where the Rake::DSL
is available.
Since tasks can be defined in different *.rake
files and they can be grouped in different namespaces, you might be tempted to treat those namespaces as if they were distinct classes with distinct methods. For example, you might create a task file that includes a prepare
helper method:
# lib/tasks/task1.rake
namespace :namespace1 do
def prepare
puts 'Task preparation #1.'
end
task :task1 do
prepare
puts 'Performing task #1.'
end
end
And then in a different task file you might define a different prepare
method:
# lib/tasks/task2.rake
namespace :namespace2 do
def prepare
puts 'Task preparation #2.'
end
task :task2 do
prepare
puts 'Performing task #2.'
end
end
But then when you run rake namespace1:task1
the results are:
Task preparation #2.
Performing task #1.
Oops. It ran the preparation
method from namespace2
. This is because Rake namespaces affect task name resolution, but they don't do anything to alter the method scoping. So when Rails loaded all tasks in the lib/tasks
folder, the prepare
method defined in namespace2
overrode the prepare
method that was originally defined in namespace1
.
If you need to have complicated tasks with many methods, it's better to push that work out into a separate Ruby class that is called by the task.
How does Rake know to look for tasks in the lib/tasks
folder?
Because Rails uses a Rakefile
that calls Rails.application.load_tasks
which loads tasks from that folder.
Why are the methods in different *.rake
files clobbering each other?
Before a task runs, all Rake tasks are loaded within the same scope, so method names need to remain unique.