Scripts With Rails Application Loaded
I often need to write some scripts for my Rails applications. These are sometimes intended to be run in development or production environments, and require that the Rails application is loaded. The most common way I’ve seen of doing this is with a rake
task:
namespace :import do
desc "Import people. Requires a file name as argument"
task :people, %i[file_path] => :environment do |_t, args|
puts "Importing people from #{args[:file_path]}"
People::Import.new(args[:file_path]).perform
puts "Done"
end
end
rake
tasks have their benefits, but the argument handling is not like most other unix programs. They are passed as an array at the end of the task name:
bash-5.2$ rake import:people[people.csv]
Importing people from people.csv
Done
Even more troubling, is that if you use zsh
(and I am!), the [
and ]
need to be escaped, or the whole argument to rake
quoted:
$ rake import:people\[people.csv\]
# OR
rake "import:people[people.csv]"
Rails runner
You can use rails runner
to run any ruby file in the context of the rails application:
# import.rb
puts "Importing people from #{ARGV.first}"
People::Import.new(ARGV.first).perform
puts "Done"
And run it by passing your file as the first argument:
$ rails runner import.rb people.csv
But you can also use rails runner
as a shebang line.
#!/usr/bin/env rails runner
# bin/import
puts "Importing people from #{ARGV.first}"
People::Import.new(ARGV.first).perform
puts "Done"
And now you can invoke that directly:
$ chmod +x bin/import
$ bin/import people.csv
The shebang line allows your script to be directly executable. Now, you can make it more ergonomic, and build up a unix-like command:
#!/usr/bin/env rails runner
# bin/import
options = {}
OptionParser.new do |parser|
parser.banner = "Usage: rails runner example.rb [options]"
parser.on("-f", "--file FILE", "Import from FILE") do |file|
options[:file] = file
end
parser.on("-h", "--help", "Prints this help") do
puts parser
exit
end
end.tap(&:parse!)
puts "Importing people from #{options[:file]}"
# ...
$ bin/import --file people.csv
# ...
$ bin/import -h
Usage: rails runner example.rb [options]
-f, --file FILE Import from FILE
-h, --help Prints this help
Conclusion
Using rails runner
as a shebang allows full access to the Rails environment in your script, without having to sacrifice command-line ergonomics.
Find me on:
- Bluesky at @ylan.segal.family.com
- Mastodon at @ylansegal@mastodon.sdf.org
- By email at
ylan@{this top domain}