Why we use the t as an arguments in rake task - ruby-on-rails

namespace :git do
desc "let's you clone a git repo by passing username and repo"
task :clone, :user, :repo do |t, args|
user = args[:user]
repo = args[:repo]
if system "git clone git#github.com:#{user}/#{repo}.git"
puts "Repository: #{repo} cloned successfully"
else
puts "There was a problem with your request, please try again later."
end
end
end
Can anyone explain why we take t as an argument here and the use of t in this task.

Task gets a block:
The first argument of the block “t” is the current task object.
The second argument “args” allows access to the task arguments.
See rake rdoc
The first argument t is not used at all in your example.

The first argument of the task definition block is the task object itself, an instance of the Rake::Task class.
If you ask "why do I need it" - you probably don't need it (yet?), but in general, it gives you an access to the task's state and instance methods, and therefore more control on how the task is executed.
For example, by default Rake engine tracks the tasks that were executed and doesn't execute them on consequent invocation attempts in the same chain, but having access to the task object you can call reenable on it, making its invocation possible again. Or you can enhance the task with some prerequisites dynamically etc etc etc.

Related

Can I detect if a rake task was triggered on the command line (as opposed to with cron, etc.)?

Of course it is unusual for rake tasks to be triggered by a controller (and kind of kludgey) but very common for them to be triggered by cron. I would like to detect from within a rake task whether it was started manually on the command line, or not.
How can I do that? This is a pretty standard thing to do in a shell script, but I'm unable to find any documentation about how to do it with a rake task.
Why the hate? People are downgrading this simply because they don't know the answer? 🤦🏼‍♂️
Here's a stab I took.
I tested this in both CL and Rails Console. I also tacked an invocation at the end of Application.rb to double check. But I haven't tested it in all the many other ways one might, so people should use this only with caution.
Likewise, I'm not certain that index 7 will be universal.
But I'm pretty sure it's accomplishable if you really want it.
task who_called: :environment do
puts case caller_locations[7].label
when "<main>" then :rails
when "invoke_task" then :cli
else
raise "unknown caller: #{location}"
end
end
Another suggestion is to always invoke the task with an ENV variable or an argument. You can assume that nil defaults to the command line, so people don't have to type unnecessary arguments.
Try this:
if defined?(Rails::Console)
....
end
Or you can check what caller[0] returns when you call from the cmd and use that in the if instead.

Writing multiple Rake tasks

I've written two Rspec tests each which invoke the same Rake task. The second task never gets run, as invoke only triggers once so I need to reenable. My issue is that I can't get the rake task to run, here is the command I'm using:
Rake::Task["product:delete"].reenable(product.id)
I get a run time error for this command:
Don't know how to build task 'product:delete[1]' Did you mean? product:delete
Anybody know how I should write this? I'm confused because in isolation I get it to pass by running:
Rake.application.invoke_task("product:delete[#{product.id}]"
You shouldn't need to pass an argument to reenable (it doesn't take one)
You should however be passing your argument to invoke (not invoke_task) rather than specifying it as part of the task name.
E.g.
Rake::Task['product:delete'].reenable
Rake::Task['product:delete'].invoke(product.id)
You could streamline it a little more perhaps by saving the task in a variable:
t = Rake::Task['product:delete']
t.renable
t.invoke(product.id)
P.S. It looks a lot like that error "Don't know how to build task 'product:delete[1]' Did you mean? product:delete" has actually come from you trying to invoke the task with the argument in the task name rather than from the reenable. Possibly as a result of trying a lot of different things.

Why does this rake task run the method twice before running the rake task?

I wanted to create a logger to output some messages to the screen as well as the log file. I had created a method in the rake task that I was going to pass the message to so I could output to both screen and log file, if required. This returned argument 1 of 0 message when run. To investigate this further I created a simple rake task below just to see what was going on.
Task
namespace :x do
desc "test"
task :y => :environment do
puts "hello"
end
def logger
puts "logger"
end
end
Surprising, when I ran the task it would run the logger method twice before running the actual task (see output).
Output
$ rake x:y
logger
logger
hello
This explained my argument error because it wouldn't have any arguments passed to the logger method if it was run before the task.
My question is two fold:
1) Why does it run the method at all as it's not referenced in the task?
2) Why does it run the method twice? (I would expect once if it was going to run it but twice is just plain odd)
I'll go back to putting all the logging in the task and remove the method. It would be useful to know why the simple example does what it does.
EDIT
I've done a screen dump showing the code and results below.

Run one rake task after another completes

I'm trying to split down a rake task that i have,
What im wanting to do is after the rake task completes, It fires off another rake task.
Is this possible and if so how?
You can use enhance to extend one task with other:
task :extra_behavior do
# extra
end
Rake::Task["first:task"].enhance do
Rake::Task[:extra_behavior].invoke
end
Reference
Reference
Passing a task as an argument to enhance causes it to run BEFORE the task you are "enhancing".
Rake::Task["task_A"].enhance(["task_B"])
# Runs task_B
# Runs task_A
Passing a task to enhance in a block causes it to run AFTER the task you are "enhancing".
Rake::Task["task_A"].enhance do
Rake::Task["task_B"].execute
end
# Runs task_A
# Runs task_B
Reference: Rake Task enhance Method Explained

"Private" Rake tasks with the Rails environment

I know I can have the following to call a list of sub-tasks and have each one utilize the Rails environment of my project:
task :main_task => [:sub_task1, :sub_task2] do
end
task :sub_task1 => :environment do
Model1.some_class_method
end
task :sub_task2 => :environment do
Model2.some_class_method
end
My questions are
Is there any way in :main_task to pass the :environment so that I don't have to explicitly put it in each sub-task?
Is there any way to make the sub-tasks be considered "private"? That is, I don't want them to be explicitly called individually. They would only ever execute from :main_task. Basically I need to read data out of one database (SQLServer) and populate another (MySQL - the Rails project's db), but I want to keep the "read" task separate from the "populate" task for good readability.
You can list the :environment task once in the parent task before the other two to have it listed only once.
task :main_task => [:environment, :sub_task1, :sub_task2] do
end
There are no "private" tasks, however you can keep them from being listed by rake -T by not putting a desc line above them. You could enforce them manually by throwing an exception if they are called directly (detecting something the parent does, or some such).
However, you would probably have a better time putting the code in a shared method or class which is not directly exposed as a rake task.

Resources