How to pass arguments into a Rake task with environment in Rails?
TLDR;
task :t, [args] => [deps]
Original Answer
When you pass in arguments to rake tasks, you can require the environment using the :needs option. For example:
desc "Testing environment and variables"
task :hello, :message, :needs => :environment do |t, args|
args.with_defaults(:message => "Thanks for logging on")
puts "Hello #{User.first.name}. #{args.message}"
end
Updated per @Peiniau's comment below
As for Rails > 3.1
task :t, arg, :needs => [deps] # deprecated
Please use
task :t, [args] => [deps]
Just to follow up on this old topic; here's what I think a current Rakefile (since a long ago) should do there. It's an upgraded and bugfixed version of the current winning answer (hgimenez):
desc "Testing environment and variables"
task :hello, [:message] => :environment do |t, args|
args.with_defaults(:message => "Thanks for logging on")
puts "Hello #{User.first.name}. #{args.message}" # Q&A above had a typo here : #{:message}
end
This is how you invoke it (http://guides.rubyonrails.org/v4.2/command_line.html#rake):
rake "hello[World]"
For multiple arguments, just add their keywords in the array of the task declaration (task :hello, [:a,:b,:c]...
), and pass them comma separated:
rake "hello[Earth,Mars,Sun,Pluto]"
Note: the number of arguments is not checked, so the odd planet is left out:)
An alternate way to go about this: use OS environment variables. Benefits of this approach:
- All dependent rake tasks get the options.
- The syntax is a lot simpler, not depending on the rake DSL which is hard to figure out and changes over time.
I have a rake task which requires three command-line options. Here's how I invoke it:
$ rake eaternet:import country=us region=or agency=multco
That's very clean, simple, and just bash syntax, which I like. Here's my rake task. Also very clean and no magic:
task import: [:environment] do
agency = agency_to_import
puts "Importing data for #{agency}..."
agency.import_businesses
end
def agency_to_import
country_code = ENV['country'] or raise "No country specified"
region_slug = ENV['region'] or raise "No region specified"
agency_slug = ENV['agency'] or raise "No agency specified"
Agency.from_slugs(country_code, region_slug, agency_slug)
end
This particular example doesn't show the use of dependencies. But if the :import
task did depend on others, they'd also have access to these options. But using the normal rake options method, they wouldn't.
Just for completeness, here the example from the docs mentioned above:
task :name, [:first_name, :last_name] => [:pre_name] do |t, args|
args.with_defaults(:first_name => "John", :last_name => "Dough")
puts "First name is #{args.first_name}"
puts "Last name is #{args.last_name}"
end
Notes:
- You may omit the
#with_defaults
call, obviously. - You have to use an
Array
for your arguments, even if there is only one. - The prerequisites do not need to be an
Array
. args
is an instance ofRake::TaskArguments
.t
is an instance ofRake::Task
.