Before starting, let us understand what tasks are in general.
To put it in simple terms, a task is piece of work to be done, usually assigned piece of work often to be finished within a certain time.
According to wiki, Rake is a software task management and build automation tool. It allows the user to specify tasks and describe dependencies as well as to group tasks in a namespace.
From the defination itself we can understand that Rake is simply a software that allows user to define and then run those tasks.
Any file that ends with an extension .rake is a Rake Task. These files/tasks can then be called and executed. All of this is possible using Rake.
You can call the defined Rake tasks, simply by using the command:
1 rake "your_rake_file"
Since version 5.0 Rails, rails allows you to call most rake commands with rails instead.
So, both the commands works perfectly to fire your tasks.
1 2 rake 'your_rake_file' rails 'your_rake_file'
You don’t have to worry about installing Rake. Rake is itself a gem, that is installed as soon as you install Rails Gem.
Below we will discuss some examples on how to create rake tasks, how to define many rake tasks under a same namespace, and many more.
Creating a simple Rake Task
All the rake tasks that you create, should be put under the /lib/tasks/ directory of your project.
As mentioned earlier, the file should end with .rake extension.
From there on, creating a Rake task is quite simple.
1 2 3 4 task :print_hello_world do desc "This task prints hello world" puts "Hello World" end
As you can see in the example above, I created a task named print_hello_world. The name of the task can also be a string, in the above example I have used symbol instead.
Inside the block, we can write any valid ruby code. In the example above, I have used desc to describe the use of the task, and then printed Hello World in the next line.
Now, to execute this task, we simple use the command:
1 2 3 rake print_hello_world # OR rails print_hello_world
Grouping many tasks within the same namespace
Suppose, instead of using a single rake tasks, we have the need of many rake tasks, that serve the same purpose.
You may have encountered this use case if you’ve ever used rake commands such as:
1 2 rails db:create rails db:migrate
In this case, both the create and migrate are rake tasks that both belong to the same namespace db.
When triggering a task that belongs to a specific namespace, we use the command in the following format:
1 rake your_namespace:your_rake_task
So, now let us learn how to create various tasks that belong to a same namespace.
1 2 3 4 5 6 7 8 namespace :mytask do task :first_task do puts "Hello World from First Task" end task :second_task do puts "Hello World from Second Task" end end
Here, we have created two tasks first_task and second_task under the namespace mytask. Now, let’s run the tasks and and inspect the output.
1 2 rake mytask:first_task #=> Hello World from First Task rake mytask:first_task #=> Hello World from Second Task
Passing arguments to a Task
Let’s talk about the cases when you want to pass arguments to a task. In our example, let us suppose that we want to print a variable that is passed while executing the rake command.
1 2 3 4 5 6 7 8 namespace :mytask desc "This task takes arguments" task :taskA, [:arg_1,:arg_2] do |task,args| puts args puts args[:arg_1] puts task end end
We have defined a new task taskA, and then also defined that the task takes two arguments arg_1 and arg_2.
This time the block takes two arguments task and args. The task arguments stores the information of the task itself, and args stores the arguments that are passed while executing the task, we can see this in the example below:
1 2 3 4 rails mytask:taskA["A","B"] #=> #<Rake::TaskArguments arg_1: A, arg_2: B> #=> A #=> mytask:taskA
The first output shows all the passed arguments while executing the task, the second output prints a specific argument, and the final output prints the task itself.
NOTE: Sometimes your zsh might throw an error while executing rake commands that take arguments. zsh might not recognize the command. In that case you will have to escape the box brackets, i.e. use
1 rake mytask:taskA\["A","B"\]
Executing one task before another
Suppose you have two tasks, task_1 and task_2, and wish to execute task_2 before task_1, you can accomplish it in the following way:
1 2 3 4 5 6 7 8 9 10 11 12 13 namespace :mytask do desc "Executing some task_2 before task_1 within the same namespace" task task_1: [:task_2] do puts "Hello from Task 1" end task :task_2 do puts "Hello from Task 2" end end
The tasks that you want to execute before task_1, must be put inside the box bracket int the order you want them to execute.
The output for the above example will be as follows:
1 2 3 rails task_1 #=> Hello from Task 2 #=> Hello from Task 1
The contents of task_2 is printed before the contents of task_1.
If you want to execute a task that belongs to a different namespace then use the following syntax:
1 2 3 task task_1: ["different_namespace:task_2"] do puts "From Nothing Task" end
Now, this will execute the task_2 in the “different_namespace” namespace before executing task_1.
Managing task execution order and passing arguments at the same time
If you want to pass arguments to your current task, and also call other tasks before executing your own task, the syntax will look as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 namespace :mytask do # Using arguments, and before calls together task :final_task, [:args_1,:args_2] => [:task_2,"different_namespace:task_2"] do |task,args| puts args[:args_1] end task :task_2 do puts "Hello World from Task 2 in the same namespace" end end namespace :different_namespace do task :task_2 do puts "Hello World from Task 2 in a different namespace" end end
When you run the final_task, you will get output as follows:
1 2 3 4 5 rails mytask:final_task["Hello World from task arguments"] #=> Hello World from Task 2 in the same namespace #=> Hello World from Task 2 in a different namespace #=> Hello World from task args