How to create rake task and pass arguments
In the Ruby domain, rake
is a Make-like utility that uses Ruby syntax to define tasks. Often used for simple, repeatable administrative tasks or for bundling a group of scripts together, Rake allows you to make the execution of your scripts more concise and manageable.
Today, we'll dive into the process of creating rake tasks and effectively passing arguments to them. Here's your step-by-step guide.
Using namespaces
Tasks can be grouped together in a namespace. This is particularly useful for organizing related tasks in a Rails application. Here's how to declare and invoke a task using a namespace:
namespace :do_some_action do
desc 'task description'
task :run do |task, args|
puts "run me!"
end
end
# usage: rake do_some_action:run
You can also call the task directly from within another rake task:
task :invoke_my_task do
Rake::Task[:my_task].invoke(123, 456)
end
Task prerequisites
Rake allows you to define prerequisites for tasks. Prerequisite tasks receive the arguments passed to the calling task. It can be used for example to put logging into a file or another status of logging. Let's see an example:
desc "move rails logger to stdout"
task verbose: [:environment] do
Rails.logger = Logger.new(STDOUT)
end
desc "move rails logger logs to debug level"
task verbose_to_debug: [:environment, :verbose] do
Rails.logger.level = Logger::DEBUG
end
desc "move rails logger logs to info level"
task verbose_to_info: [:environment, :verbose] do
Rails.logger.level = Logger::INFO
end
namespace :do_some_action do
desc 'task description'
task run: :verbose_to_debug do |task, args| # add verbose_to_debug
puts "put rails loggging into debug logger"
User.last # print to log as debug
end
end
# usage: rake do_some_action:run
Using the default way
We can also go with standard parameter passing, but this method is tricky because we need to go with hacky array
was when passing multiple parameters into rake task.
namespace :do_some_action do
desc 'task description'
task :run, [:user_id, :project_id] do |task, args|
# add default when needed
args.with_defaults(:user_id => '111', :project_id => '222')
options = args.to_hash
if options.values.all?(&:nil?)
puts "Usage: rake do_some_action:run user_id=123 project_id=246"
next
end
raise ArgumentError, 'user_id is required' if options[:user_id].blank?
raise ArgumentError, 'project_id is required' if options[:project_id].blank?
puts "do some stuff with passed params #{options}"
end
end
# usage: be rake do_some_action:run - for default values
# usage: rake do_some_action:run\[123,456\] - for specific values
To run this task with arguments, you would run rake do_some_action:run\[123,456\]
. Note the use of parentheses [ ]
to pass the arguments and the lack of spaces between them. When you add spacing, then you will see an error.
Using OptParse
OptParse gem is a command line option parser class. It is much more advanced, but also easier to use than GetoptLong, and is a more Ruby-orientated solution.
require 'optparse'
namespace :do_some_action do
task :run, [:user_id, :project_id] do |t, args|
options = {}
opts = OptionParser.new
opts.banner = "Usage: rake do_some_action:run [options]"
opts.on("-u", "--user_id ARG", Integer) { |num1| options[:user_id] = num1 }
opts.on("-p", "--project_id ARG", Integer) { |num2| options[:project_id] = num2 }
args = opts.order!(ARGV) {}
opts.parse!(args)
if options.values.all?(&:nil?)
puts "Usage: rake do_some_action:run user_id=123 project_id=246"
next
end
raise ArgumentError, 'user_id is required' if options[:user_id].blank?
raise ArgumentError, 'project_id is required' if options[:project_id].blank?
puts "do some stuff with passed params #{options}"
end
end
# usage: rake do_some_action:run -- --user_id=123 --project_id=456
With this method, we're passing variables into options
hash variable.
Using ARGV
Another method is to use ARGV and handle these parameters
namespace :do_some_action do
task :run do
options = {
user_id: ARGV[1]&.split('=')&.last,
project_id: ARGV[2]&.split('=')&.last,
}
if options.values.all?(&:nil?)
puts "Usage: rake do_some_action:run user_id=123 project_id=456"
next
end
raise ArgumentError, 'user_id is required' if options[:user_id].blank?
raise ArgumentError, 'project_id is required' if options[:project_id].blank?
puts "do some stuff with passed params #{options}"
end
end
# usage: rake do_some_action:run user_id=123 project_id=456
Using linux-style passing arguments
We have (I think the best) method for passing parameters via ENV.
namespace :do_some_action do
task :run do
options = {
user_id: ENV['user_id'],
project_id: ENV['project_id']
}
if options.values.all?(&:nil?)
puts "Usage: rake do_some_action:run user_id=123 project_id=246"
next
end
raise ArgumentError, 'user_id is required' if options[:user_id].blank?
raise ArgumentError, 'project_id is required' if options[:project_id].blank?
puts "do some stuff with passed params #{options}"
end
end
# usage: rake do_some_action:run user_id=123 project_id=246
In the above rake task, the arguments user_id
and project_id
are passed as environment variables and it's easy to understand for everybody without using hacky doubled --
like rake do_some_action:run –- --user_id=123
or even worse passing arrays into rake task.
Wrapping up
Using arguments in your rake tasks can be difficult if you don't know any tricks, but if you know how to handle passing parameters - it can be great and very useful in your daily work.
Happy coding!