Rake tasks, arguments, and external scripts
I’ve previously covered how to use an external script from within a Rake task. This time, we want to be able to pass an optional argument to our task, that will be used within our external script, too.
Background
In this case, I was uploading stock information and (in case I had to stop midway through), I wanted to be able to start the upload from an arbitrary serial number. In addition, as explained above, I wanted to be able to have a standalone script to do the actual uploading, so that I could run the script on its own if necessary.
Setting up the Rake task
Since we want to use an argument in our task, we’ll need to pass it in:
task :load, [:starting_case_number] => [:environment] do |task, args|
# ...
end
As you can see, we’ve got a
:load
task that takes one argument. This task requires the Rails environment, and we pass both the task and argument list to the task’s block. In the case above, the argument list contains only one argument; but if you had several, you’d simply add them to the array.
Then, we need to simply reference the active record objects we’ll be using, so that their loading is triggered:
task :load, [:starting_serial_number] => [:environment] do |task, args|
# Referencing an ActiveRecord class triggers the actual loading of
# that class so it can then be used within the script.
# Without this, the ActiveRecord models aren't loaded, even with the
# `:environment` dependency
CatalogItem
Site
end
Then, we need to pass the argument to the outside script. One method to achieve this is using a global variable, then loading the script. Since the script is being loaded, it will automatically gain access to the global variable.
desc "Load retail stock from CSV file"
task :load, [:starting_serial_number] => [:environment] do |task, args|
# Referencing an ActiveRecord class triggers the actual loading of
# that class so it can then be used within the script.
# Without this, the ActiveRecord models aren't loaded, even with the
# `:environment` dependency
CatalogItem
Site
# we set a global variable and use load so that the console output
# will be displayed
$starting_serial_number = args[:starting_serial_number]
puts "Loading retail stock with script at #{path}"
load File.join(script_base_path, "retail_stock_upload_script.rb")
end
The external script
Form within the external script, we simply set the starting serial number as appropriate:
# It is possible to provide a serial number with which to start
# the data upload.
# All serial numbers up to the provided one will be skipped.
# This behvaior is useful if the process is interupted and must be
# started again from a given serial number.
def get_starting_serial_number
# this file can be executed as a standalone or through a Rake task
# we need to determine which case this is, so we can correclty
# determine the case number if it awas provided
if defined? Rake
$starting_serial_number # is set in the rake task
else
ARGV.first
end
end
then in your main code, call
starting_serial_number = get_starting_serial_number
And voilà, you’ve got you external script working fine: you can call it from a Rake task, or directly from the command line. In each case, the optional argument will be loaded properly.
Would you like to see more Elixir content like this? Sign up to my mailing list so I can gauge how much interest there is in this type of content.