I have created a rake task in the file called att_rec_for_emp.rake . in this file i have the following task.
task hello(parameter): :environment do
p "{parameter}"
end
how can i call this rake task in the controller action by passing parameters?
i have an action like this
def call_task
emp = Employee.first
Rake::Task[ 'att_rec_for_emp:hello("hello world")' ].invoke
redirect_to :root , :notice => "message fine"
end
and in config/initialisers/rake.rb i have the following statement.
Rake.load_rakefile Rails.root.join( 'lib','tasks','att_rec_for_emp.rake' )
but still the task is not executing. getting the error
Don't know how to build task 'att_rec_for_emp:hello'
I think I got it working. Tweak from here.
Here's what I did:
lib/tasks/att_rec_for_emp.rake
task :hello, [:parameter] => :environment do |t, args|
p "#{args[:parameter]}"
end
app/controllers/your_controller.rb
Rake::Task.clear
YourAppName::Application.load_tasks
class YourController < ApplicationController
def call_task
Rake::Task[:hello].reenable
Rake::Task[:hello].invoke('hi world')
end
end
You could also put those first two lines (above YourController class definition) in an initializer.
Note: Your approach of loading the Rake file in an initializer should work too but my setup is a little different. I have my entire lib directory loaded in application.rb.
config/application.rb
config.autoload_paths += Dir["#{config.root}/lib"]
Hope that helps!
Try adding this line to your controller:
YourAppName::Application.load_tasks
Or, change the directory name from initialisers to initializers.
Related
I'm attempting to use the whenever to execute a method every 30 minutes. However I'm having some trouble setting it up.
schedule.rb
every 1.minutes do
runner "Post.winner"
end
post.rb
class Post < ActiveRecord::Base
module Post
def winner
#do some stuff that saves a new value in database
I don't think the runner is working because the field that I save a value to still shows up as nil in the console.
You most probably do not want to run a controller method (eg you have no request to serve there). Either create a runner from a class or module.
# schedule.rb
every 30.minutes do
runner "Post.winner"
end
#lib/post.rb
module Post
def self.winner
...
end
end
or a rake task in lib/tasks/
# schedule.rb
every 30.minutes do
rake post:winner
end
#lib/tasks/post.rake
namespace :post do
desc 'calculate winner'
task :winner do
...
end
end
I'm almost sure you have a model Post. Create a class method:
class Post
...
def self.winner
...
end
end
But if you are using Post.winner only for the schedule, I prefer a rake task as #xlembouras suggested.
I m working in rails.i want to call a function(show) of class "twitter" in searcht1 which is in "lib" within a same directory from rake task.
lib/task/search.rake:
require_relative "lib/Searcht1"
namespace :Searcht do
task :search => :environment do
obj=Twitter.new
obj.show
end
end
and the class inside the "searcht1.rb" is like this
class Twitter
def show
"anylogic"
end
end
but it is not calling that function.and i m not getting any result.
greatly aprreciate any help
I know this question is a bit outdated, but I had the problem in my rails5 app and this is how I keep my tasks clean :)
Please make a subdir searchdir in lib/tasks => lib/tasks/searchdir and put your referenced file searcht1.rb in there.
Now you can reference it in your rake file.
Please keep in mind: it is run from the referenced file.
# in lib/tasks/search.rake
namespace :Searcht do
task :search => :environment do
require_relative "searchdir/searcht1"
end
end
make your code run here:
# in lib/tasks/searchdir/searcht1.rb
class Twitter
def show
"anylogic"
end
end
obj=Twitter.new
obj.show
It is possible to call a method which is in the same rake file as the task? In the code below you can see that I have the method call get_search_url which will be assigned to url.
namespace :populate do
desc "ETC"
task :db => :environment do
Report.where(link: "").each do |word|
url = get_search_url(word.name)
doc = Nokogiri::HTML(open(url))
word.update_columns(link: link)
end
end
def get_search_url(keyword)
return "URL/keyword"
end
end
Yes it is absolutely possible. Just define those methods after the namespace ;)
namespace :populate do
desc "ETC"
task :db => :environment do
Report.where(link: "").each do |word|
url = get_search_url(word.name)
doc = Nokogiri::HTML(open(url))
word.update_columns(link: link)
end
end
end
def get_search_url(keyword)
return "URL/keyword"
end
However if you define the same method in two different rake tasks, they will both be globally loaded when running rake, and one of the method definitions will be redefined / overwritten by the other!
Better practice is to define methods in a separate module and then include that module in your rake file.
See https://kevinjalbert.com/defined_methods-in-rake-tasks-you-re-gonna-have-a-bad-time/ (Solution #3)
I have a method I have added on Date that looks like this:
class Date
def days_different(date)
Float(self-date)
end
end
This works great in the rest of my application, but I also have a rake task in lib/tasks/database.rake that uses this where this is not being loaded despite having the => :environment dependency on the task (greatly simplified test version shown below).
task :test_days_different => :environment do
date = 2.days.ago
puts date.days_different(DateTime.now)
end
Strangely, rake:test loads the helper function when it loads its environment so I'm completely baffled as to why this isn't loading in rake db
Any ideas?
You did not mention where you put the extended Date class but I think you have to require 'date' in the rake file.
This code snippet is not working without the require statement:
require 'date'
class Date
def days_different(date)
Float(self-date)
end
end
date = Date.new(2001,2,1)
puts date.days_different(DateTime.now)
Using Rails 2.3.10
If my lib/tasks looks like this
lib/tasks
- a.rake
- b.rake
a.rake looks like this:
namespace :a do
desc "Task A"
task(:a=>:environment)do
msg('I AM TASK A')
end
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
b.rake looks like this
namespace :b do
desc "Task B"
task(:b=>:environment)do
msg('I AM TASK B')
end
def msg(msg)
puts "MSG SENT FROM Task B: #{msg}"
end
end
Then when I run task a
rake a RAILS_ENV=sandbox
The output is
"MSG SENT FROM Task B: I AM TASK A"
So the msg() helper method defined in a.rake does not get called. Rather that defined in b.rake gets called. (What's more, if I have a c.rake - then it's msg helper method gets called when I run task a.
Is this method namespace clashing known behavior?
I would have thought the namespacing would have prevented this.
Thanks
What you observe is that methods in rake files namespaces redefine previously defined methods with the same name. The reason for this is that Rake namespaces are very different than Ruby namespaces (classes or modules), in fact they only serve as a namespace for the names of the tasks defined in them, but nothing else. Thus, task a becomes task a:a if placed in the a namespace but other code outside the tasks shares the same global namespace.
This fact, together with the fact that Rake loads all tasks before running the given task, explains why the method gets redefined.
TL;DR: Solutions / hints for the name clashes
You cannot expect that two methods with the same name (or any other code) placed inside separate namespaces but outside tasks will work properly. Nevertheless, here are a couple of hints to solve such situation:
Place the methods inside the tasks. If both msg methods were defined inside the a:a and b:b tasks, then both rake tasks would run properly and would display the expected messages.
If you need to use the code from the rake's namespace in multiple rake tasks, extract the methods / code to a real Ruby namespace, such as two modules, and include the code in the tasks that need it. Consider this rewrite of the sample rakes:
# lib/tasks/a.rake:
module HelperMethodsA
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
namespace :a do
desc "Task A"
task(:a => :environment) do
include HelperMethodsA
msg('I AM TASK A')
end
end
# lib/tasks/b.rake:
module HelperMethodsB
def msg(msg)
puts "MSG SENT FROM Task B: #{msg}"
end
end
namespace :b do
desc "Task B"
task(:b => :environment) do
include HelperMethodsB
msg('I AM TASK B')
end
end
Because the two modules have different names and because they are included in the respective tasks, both rake tasks will again run as expected.
Now, let's prove the above claims with the help of the source code...
Proof that Rake loads all tasks first and why it does so
This one's easy. In the main Rakefile you'll always find the following line:
Rails.application.load_tasks
This method eventually calls the following code from the Rails engine:
def run_tasks_blocks(*) #:nodoc:
super
paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
end
Thus, it searches the lib/tasks directories for all rake files and loads them one after each other, in a sorted order. That's why the b.rake file will be loaded after a.rake and whatever is inside it will potentially redefine the code from a.rake and all previously loaded rake files.
Rake has to load all rake files simply because the rake namespace names do not have to be the same as rake filenames, so the rake filename cannot be inferred from the task / namespace name.
Proof that rake's namespaces don't constitute a real Ruby-like namespace
Upon loading the rake files, the Rake DSL statements get executed, and also the namespace method. The method takes the block of code defined inside it and executes it (using yield) in the context of the Rake.application object which is a singleton object of the Rake::Application class that is shared among all rake tasks. There is no dynamic module / class created for the namespace, it's just executed in the main object context.
# this reuses the shared Rake.application object and executes the namespace code inside it
def namespace(name=nil, &block)
# ...
Rake.application.in_namespace(name, &block)
end
# the namespace block is yielded in the context of Rake.application shared object
def in_namespace(name)
# ...
#scope = Scope.new(name, #scope)
ns = NameSpace.new(self, #scope)
yield(ns)
# ...
end
See the relevant sources here and here.
Rake tasks DO constitute ruby namespaces
With Rake tasks themselves, the situation is different, though. For each task, a separate object of the Rake::Task class (or of a similar class) is created and the task code is run inside this object's context. The creation of the object is done in the intern method in the task manager:
def intern(task_class, task_name)
#tasks[task_name.to_s] ||= task_class.new(task_name, self)
end
A quote form the Rake's author
Finally, all this is confirmed by this interesting discussion on github that deals with a very similar and related issue, and from which we can quote Jim Weirich, the original author of Rake:
Since namespaces don't introduce real method scopes, the only real possibility for a scope is the DSL module.
...
Perhaps, someday, the Rake namespaces will become full class scoped entities with a place to hang lazy let definitions, but we are not there yet.
Use namespace like the following:
namespace :rake_a do
desc "Task A"
task(:a=>:environment)do
msg('I AM TASK A')
end
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
The rake namespace is only intended for rake tasks.
See the Rake documentations:
The NameSpace class will lookup task names in the the scope defined by a namespace command.
You can create a module along with your rake namespace to cover this problem:
module A do
module_functions
def msg(msg)
puts "MSG SENT FROM Task A: #{msg}"
end
end
namespace :a do
desc "Task A"
task(:a=>:environment)do
A.msg('I AM TASK A')
end
end