Pass Hash as Parameter to Rake Task - ruby-on-rails

I've got a rake task
task :post_hit, [:host, :title, :description, :model, :num_assignments, :reward, :lifetime, :qualifications, :p, :opts] => :environment do |t, args|
:p needs to be a hash, but if I try:
rake turkee:post_hit["http://www.staging.collegesportsbluebook.com","LS Info","Fill In Player First Name","MechanicalTurk",100,0.01,2,{},{id: 5},{}]
It errors out saying that id: could not be parsed (the space seemed to do something).
If I tried:
rake turkee:post_hit["http://www.staging.collegesportsbluebook.com","LS Info","Fill In Player First Name","MechanicalTurk",100,0.01,2,{},{"id: 5"},{}]
the who string "id: 5" was being interpreted as a single string.
Are we not allowed to pass hashes to rake tasks?

I use querystring-like parameters and parse them with Rack::Utils.parse_nested_query
Here's how I do it
require 'rack/utils' # needed for Rack::Utils.parse_nested_query
namespace :foo do
task :bar, [ :args_expr ] => :environment do |t, args|
args.with_defaults(:args_expr => "name=abdo&fruits[]=bananas&fruits[]=dates")
options = Rack::Utils.parse_nested_query(args[:args_expr])
puts options
end
end
And I call it like this: (notice how arrays and hashes are passed)
bundle exec rake "foo:bar[name=abdo&fruits[]=apples&fruits[]=oranges&hash[foo]=bar&hash[cool]=notmuch]"
Output:
{"name"=>"abdo", "fruits"=>["apples", "oranges"], "hash"=>{"foo"=>"bar", "cool"=>"notmuch"}}

When you issue a rake task via the terminal, you are in the UNIX or Bash environment, so you need to obey the rules of that language, which as far as I can tell doesn't include hashes. I could be wrong though.
http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html#toc5
This doesn't mean that whoever wrote the rake task didn't do something clever to parse a string into a hash. If I were you and trying to figure it out I would have a look at the source code and see how that rake task parses it's variables.
PS. If it's a gem you are using and you are using bundler as well, you can issue bundle open gem_name to open up the source, rake tasks generally end in a .rake...

Try declaring your :p variable in task as a hash maybe? :p => {}
task :post_hit, [:host, :title, :description, :model, :num_assignments, :reward, :lifetime, :qualifications, :p => {}, :opts

Related

Problem with passing argument to rake task

I am coding in Ruby 2.3.1p112 and Rails 4.2.7.1 and encounter this bug(?) when trying to use if-statement inside of one of the rake files.
I call this rake task:
task :bar, [:argument] => :environment do |_task, arg|
binding.pry
if arg.blank?
# do stuff
else
# do other stuff
end
end
from this worker:
# ...
def perform(location = nil)
Rake::Task["foo:bar"].execute(location)
end
# ...
And when the code hits the binding.pry line I get the following issue:
Is it a bug indeed or am I lacking some basic knowledge around here?
Thanks!
You want
arg[:argument].blank?
because arg is a hash with :argument key.
On a side note: the following would be more descriptive definition of a task (note plural args and location since it looks like you're passing location):
task :bar, [:location] => :environment do |_task, args|
if args[:location].blank?
# do stuff
else
# do other stuff
end
end

Rake Task environment variable w/Command Line Arguments

So I was getting some "Uninitalized constants" on my rake task, and I did some googling and found that the environment variable needed to be loaded in. However im also using a command line argument and im not sure if the positioning is correct or what:
desc "Wipes Specific User"
task :clean_user => environment [:user] do |t, args|
puts "Running clean_user for #{args[:user]}..."
Core::Stuff.find(args[:user]).wipe_user
end
Without the environment variable somewhere I get complains about Core::Stuff being uninitialized, but Im trying to pass :user via CL. (This is just a sample rake task to make sure stuff works).
Am I missing something?
edit: Fixing the issue with:
task :clean_user, [:user] => :environment however now it seems to be loading my PATH into the argument (I get an error complaining how "Core::Stuff cannot find a user id with id of "" . So it's like it's using my CL path as the ID?
The docs in the gem specify:
task task_name, arguments => dependencies
That means your code needs to be:
task :clean_user, [:user] => :environment do |t, args|

I don't understand how to add arguments to a rake task. (Excerpt from the documentation)

I'm trying to create a custom rake task that takes in two arguments and uses them in my code.
I'm looking at the rails documentation and I see this excerpt for running a rails task with an argument:
task :task_name, [:arg_1] => [:pre_1, :pre_2] do |t, args|
# You can use args from here
end
The rake task can then be invoked like this:
bin/rake "task_name[value 1]"
However, this is way too vague for me. The rails documentation fails to give a concrete example of a rake task with an argument.
For example, I'm looking at this code and I'm thinking what does bin/rake "task_name[value 1]" do? What is [:pre1, :pre2]?
Additionally, I've found some other fantastic links that do things a little bit differently. Here are the links.
Thoughtbot version
In the thoughtbot version that have this example
task :send, [:username] => [:environment] do |t, args|
Tweet.send(args[:username])
end
What is the [:username => [:environment]? its different than the official rails docs.
Here is another:
4 ways to write rake tasks with arguments
I've also looked at the officail optparser documentation and that too has a different way of making it work.
All I want is for this example code that I have to work on my .rake file:
require 'optparse'
task :add do
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: rake add"
opts.on("-o", "--one ARGV", Integer) { |one| options[:one] = one }
opts.on("-t", "--two ARGV", Integer) { |two| options[:two] = two }
end.parse!
puts options[:one].to_i + options[:two].to_i
end
The code fails because of invalid option: -o. I just want to make this work so I can move on. Does anyone have any thoughts?
Here is one of my rake tasks with arguments:
namespace :admin do
task :create_user, [:user_email, :user_password, :is_superadmin] => :environment do |t, args|
email = args[:email]
password = args[:password]
is_superadmin = args[:is_superadmin]
... lots of fun code ...
end
end
and I invoke this task like this:
rake admin:create_user['admin#example.com','password',true]
EDIT
To pass flags in you can do something like this:
task :test_task do |t, args|
options = {a: nil, b: nil}
OptionParser.new do |opts|
opts.banner = "Usage: admin:test_task [options]"
opts.on("--a", "-A", "Adds a") do |a|
options[:a] = true
end
opts.on("--b", "-B", "Adds b") do |b|
options[:b] = true
end
end.parse!
puts options.inspect
end
And examples of invoking it:
rake admin:test_task -A -B
rake admin:test_task -A
rake admin:test_task -B

rake task with multiple parameters - I got stuck

The rake task itself:
desc "This task creates a new user"
task :create_user, [:email, :password] => :environment do |t, args|
trole = Role.find_by_name('translator')
User.create(
:email => args.email,
:password => args.password,
:password_confirmation => args.password,
:role_id => trole.id)
end
The call:
rake create_user[user#host.com,password]
The output:
rake aborted!
Don't know how to build task 'create_user'
I really got stuck. All the advices I've found, even here, on StackOverflow, either don't cover the situation with two parameters, or are outdated/not working. Please help!
The syntax you've written should work fine in bash, so I'm guessing you're using zsh?
If so, it can't parse the [] correctly and these need to be escaped.
Try using:
rake create_user\[user#host.com,password\]
instead.

How to pass arguments into a Rake task with environment in Rails? [duplicate]

This question already has answers here:
How to pass command line arguments to a rake task
(20 answers)
Closed 5 years ago.
I am able to pass in arguments as follows:
desc "Testing args"
task: :hello, :user, :message do |t, args|
args.with_defaults(:message => "Thanks for logging on")
puts "Hello #{args[:user]}. #{:message}"
end
I am also able to load the current environment for a Rails application
desc "Testing environment"
task: :hello => :environment do
puts "Hello #{User.first.name}."
end
What I would like to do is be able to have variables and environment
desc "Testing environment and variables"
task: :hello => :environment, :message do |t, args|
args.with_defaults(:message => "Thanks for logging on")
puts "Hello #{User.first.name}. #{:message}"
end
But that is not a valid task call. Does anyone know how I can achieve this?
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:)
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 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 of Rake::TaskArguments.
t is an instance of Rake::Task.
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.
While these solutions work, in my opinion this is overly complicated.
Also, if you do it this way in zsh, you'll get errors if the brackets in your array aren't escaped with '\'.
I recommend using the ARGV array, which works fine, is much simpler, and is less prone to error. E.g:
namespace :my_example do
desc "Something"
task :my_task => :environment do
puts ARGV.inspect
end
end
then
rake my_example:my_task 1 2 3
#=> ["my_example:my_task", "1", "2", "3"]
The only thing you need to keep in mind is that ARGV[0] is the process name, so use only ARGV[1..-1].
I realize that strictly speaking this does not answer the question, as it does not make use of :environment as part of the solution. But OP did not state why he included that stipulation so it might still apply to his use case.

Resources