Problem with passing argument to rake task - ruby-on-rails

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

Related

A General Method to be invoked before every rake execution

In my rails project (Rails 3.1, Ruby 1.9.3) there are around 40 rake tasks defined. The requirement is that I should be able to create an entry (the rake details) in a database table right when we start each rake. The details I need are the rake name, arguments, start time and end time. For this purpose, I don't want rake files to be updated with the code. Is it possible to do this outside the scope of rake files.
Any help would be greatly appreciated!!
Try this
https://github.com/guillermo/rake-hooks
For example in your Rakefile
require 'rake/hooks'
task :say_hello do
puts "Good Morning !"
end
before :say_hello do
puts "Hi !"
end
#For multiple tasks
namespace :greetings do
task :hola do puts "Hola!" end ;
task :bonjour do puts "Bonjour!" end ;
task :gday do puts "G'day!" end ;
end
before "greetings:hola", "greetings:bonjour", "greetings:gday" do
puts "Hello!"
end
rake greetings:hola # => "Hello! Hola!"
This seems to be a bit awkward, But it may help others.
Rake.application.top_level_tasks
will return an array of information including Rake name and its arguments.
Reference attached below.
pry(main)> a = Rake.application.top_level_tasks
=> ["import_data[client1,", "data.txt]"]
When you create rake task, you can pass a parent task which will run before your task:
task my_task: :my_parent_task do
# ...
end
If your task depends from more than 1 task, you can pass an array of parent tasks
task my_task: [:my_prev_task, :my_another_prev_task] do
# ...
end

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

How do I access one of my models from within a ruby script in the /lib/ folder in my Rails 3 app?

I tried putting my script in a class that inherited from my model, like so:
class ScriptName < MyModel
But when I ran rake my_script at the command-line, I got this error:
rake aborted!
uninitialized constant MyModel
What am I doing wrong?
Also, should I name my file my_script.rb or my_script.rake?
Just require the file. I do this in one of my rake tasks (which I name my_script.rake)
require "#{Rails.root.to_s}/app/models/my_model.rb"
Here's a full example
# lib/tasks/my_script.rake
require "#{Rails.root.to_s}/app/models/video.rb"
class Vid2 < Video
def self.say_hello
"Hello I am vid2"
end
end
namespace :stuff do
desc "hello"
task :hello => :environment do
puts "saying hello..."
puts Vid2.say_hello
puts "Finished!"
end
end
But a better design is to have the rake task simply call a helper method. The benefits are that it's easier to scan the available rake tasks, easier to debug, and the code the rake task runs becomes very testable. You could add a rake_helper_spec.rb file for example.
# /lib/rake_helper.rb
class Vid2 < Video
def self.say_hello
"Hello I am vid2"
end
end
# lib/tasks/myscript.rake
namespace :stuff do
desc "hello"
task :hello => :environment do
Vid2.say_hello
end
end
All I had to do to get this to work was put my requires above the task specification, and then just declare the :environment flag like so:
task :my_script => :environment do
#some code here
end
Just by doing that, gave me access to all my models. I didn't need to require 'active_record' or even require my model.
Just specified environment and all my models were accessible.
I was also having a problem with Nokogiri, all I did was removed it from the top of my file as a require and added it to my Gemfile.

Calling a method before a task

Is there any way in rails to call a method, such as before, automatically when running a rake task I've built?
Let's say we have
namespace :migrate do
def before
# do this before all tasks
end
desc 'migrate authors from legacy database'
task :authors => :environment do
# some code here
end
end
I want to the before method to run everytime a task runs.
See if this helps: http://www.rubyflow.com/items/4104

How can I run a rake task from a delayed_job

I'd like to run a rake task (apn:notifications:deliver from the apn_on_rails gem) from a delayed_job. In other words, I'd like enqueue a delayed job which will call the apn:notifications:deliver rake task.
I found this code http://pastie.org/157390 from http://geminstallthat.wordpress.com/2008/02/25/run-rake-tasks-with-delayedjob-dj/.
I added this code as DelayedRake.rb to my lib directory:
require 'rake'
require 'fileutils'
class DelayedRake
def initialize(task, options = {})
#task = task
#options = options
end
##
# Called by Delayed::Job.
def perform
FileUtils.cd RAILS_ROOT
#rake = Rake::Application.new
Rake.application = #rake
### Load all the Rake Tasks.
Dir[ "./lib/tasks/**/*.rake" ].each { |ext| load ext }
#options.stringify_keys!.each do |key, value|
ENV[key] = value
end
begin
#rake[#task].invoke
rescue => e
RAILS_DEFAULT_LOGGER.error "[ERROR]: task \"#{#task}\" failed. #{e}"
end
end
end
Everything runs fine until the delayed_job runs and it complains:
[ERROR]: task "apn:notifications:deliver" failed. Don't know how to build task 'apn:notifications:deliver'
How do I let it know about apn_on_rails? I'd tried require 'apn_on_rails_tasks' at the top of DelayedRake which didn't do anything. I also tried changing the directory of rake tasks to ./lib/tasks/*.rake
I'm somewhat new to Ruby/Rails. This is running on 2.3.5 on heroku.
Why don't do just a system call ?
system "rake apn:notifications:deliver"
I believe it's easier if you call it as a separate process. See 5 ways to run commands from Ruby.
def perform
`rake -f #{Rails.root.join("Rakefile")} #{#task}`
end
If you want to capture any errors, you should capture STDERR as shown in the article.

Resources