Can you call a class method from a rakefile (scheduler.rake)?
I am using the Heroku Scheduler add-on and wrote a task that calls a class method but I receive an error when I run 'heroku run rake auto_start_games'
Connecting to database specified by DATABASE_URL
rake aborted!
compared with non class/module
Here is my task code:
task :auto_start_games => :environment do
all_Active_Games = Game.where(:game_active => 1)
not_flag = all_Active_Games > 0
started_games = []
unless all_Active_Games.length == 0
all_Active_Games.each do |x|
if x.players >= 2
x.winning_structure = 1 if x.players < 3
Comments.gameStartComment(x.id)
Game.gameHasStartedPush(x)
x.game_initialized = 1
x.was_recently_initiated = 1
started_games << x.id
else
Game.addDaytoStartandEnd(x.id)
Comment.gamePostponedComment(x.id)
end
end
end
puts "started games #{started_games}"
end
When you invoke Rake, you can pass the --trace flag to it. This should give you a backtrace, which I suspect is going to tell you the error is on the line not_flag = all_Active_Games > 0, because all_Active_Games is an ActiveRecord relation, but you're trying to compare it to the integer 0. Bascially, you have a type error. In a static language, this wouldn't even compile.
It would also be good to also fix your indentation, choose more descriptive variable names (x -> game)
Related
I got a rake task which invokes other rake tasks, so my development data can be easily reset.
the first rake task (lib/tasks/populate.rake)
# Rake task to populate development database with test data
# Run it with "rake db:populate"
namespace :db do
desc 'Erase and fill database'
task populate: :environment do
...
Rake::Task['test_data:create_company_plans'].invoke
Rake::Task['test_data:create_companies'].invoke
Rake::Task['test_data:create_users'].invoke
...
end
end
the second rake task (lib/tasks/populate_sub_scripts/create_company_plans.rake)
namespace :test_data do
desc 'Create Company Plans'
task create_company_plans: :environment do
Company::ProfilePlan.create!(name: 'Basic', trial_period_days: 30, price_monthly_cents: 4000)
Company::ProfilePlan.create!(name: 'Professional', trial_period_days: 30, price_monthly_cents: 27_500)
Company::ProfilePlan.create!(name: 'Enterprise', trial_period_days: 30, price_monthly_cents: 78_500)
end
end
when I run bin/rake db:populate then i get this error
rake aborted! LoadError: Unable to autoload constant
Company::ProfilePlan, expected
/home/.../app/models/company/profile_plan.rb to define it
but when I run the second rake task independently it works well.
The model (path: /home/.../app/models/company/profile_plan.rb)
class Company::ProfilePlan < ActiveRecord::Base
# == Constants ============================================================
# == Attributes ===========================================================
# == Extensions ===========================================================
monetize :price_monthly_cents
# == Relationships ========================================================
has_many :profile_subscriptions
# == Validations ==========================================================
# == Scopes ===============================================================
# == Callbacks ============================================================
# == Class Methods ========================================================
# == Instance Methods =====================================================
end
Rails 5.0.1
Ruby 2.4.0
The App was just upgraded from 4.2 to 5
It works when I require the whole path:
require "#{Rails.root}/app/models/company/profile_plan.rb"
But this seems strange to me, because in the error message rails has the correct path to the Model. Does someone know why I have to require the file when invoked from another rake task?
Thank you very much
Well, it seems that rake doesn't eager load, so when you call the create_company_plans.rake alone it loads the referred objects, however when you invoke it from another rake, it doesn't know you will need them and so they are not loaded.
You can take a look at this other QA which was similar to yours.
I think maybe you don't need to require the whole path, just:
require 'models/company/profile_plan'
From what I understand, you can probably overcome the problem by reenable ing and then revoke ing the task as given below. Pardon me if this doesn't work.
['test_data:create_company_plans', 'test_data:create_companies'].each do |task|
Rake::Task[task].reenable
Rake::Task[task].invoke
end
There is more info on this stackoverflow question how-to-run-rake-tasks-from-within-rake-tasks .
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 have a delayed job which is implemented as a model method (see below). If I use delayed_job daemon it ran and died silently. Not one job got complete and no logged message was found. But if I use RAILS_ENV=production rake jobs:work everything works OK.
I don't know why, even if an exception is thrown it should appear in the log, but there is none. And if there's something wrong with the logic then why the rake job succeeded?
def recalc(params)
last_known = self
t = nil # target(self)
target_date = self.as_on.yesterday
success = true
saved = -1
# cater for the first one
TimeSlot.where(employee_id:self.employee_id).where('incurred_on >= ?', self.as_on).order('incurred_on ASC').each do |ts|
# loop
if (ts.incurred_on >= target_date) then
if !t.nil? && target_date.day <=7 # roll over to a new month
t.bal_sick += 4 # add 4 days
if t.bal_sick > 40
overflow = t.bal_sick-40
t.bal_sick = 40
t.bal_sick2 += overflow
t.bal_sick2 = 120 if t.bal_sick2 > 120 # overflow again
end
end
unless saved<0
success = t.save
last_known = t
end
if success
saved += 1
t = target(last_known)
target_date = t.as_on
else
logger.warn("Recalc cannot saved a record for #{t.errors.first}")
logger.warn(t.inspect)
return
end
end
if ts.types.include? 'overtime'
t.bal_ot += ts.hours.to_i
t.bal_ot = 100 if t.bal_ot >100
elsif ts.types.include? 'toil'
t.bal_ot -= ts.hours.to_i
elsif ts.types.include? 'vacation'
t.bal_vacation -= ts.hours
elsif ts.types.include? 'sick1'
t.bal_sick -= ts.hours
end
end
logger.info("Recalc saved %d records"% saved)
end
After reading https://github.com/collectiveidea/delayed_job/wiki/Common-problems I found that I've missed out "specify your rails environment", i.e. RAILS_ENV=production bin/delayed_job start, the default environment appears to be development.
But why the default environment is development? It should be production. If I am in development I'd rather do rake jobs:work
I have a large database with 4+ million addresses/records.
The rake command (below) worked fine when the database was a small test set, but now with the large database it just simply stalls.
rake geocode:all CLASS=YourModel
2 questions:
1. Is there any simple method to have geocoder code a null/nil lat and long when the records are called (on the fly). I have a feeling that this would be hard.
2. Anyone else have problems with geocode-ing a large dataset and using the rake command?
Thanks!
Update:
I create pull request based on this answer and now you can use batch in geocoder:
rake geocode:all CLASS=YourModel SLEEP=0.25 BATCH=100
I would use this solution for large database, i take it from geocoder gem rake task:
You can refine this for your needs.
Some example create rake task:
namespace :geocode_my_data do
desc "Geocode all objects in my databse."
task all: :environment do
klass = User
klass.where(geocoded: false).find_each(limit: 100) do |obj|
obj.geocode; obj.save
end
end
end
$> rake geocode_my_data:all
Used below code and put it into my lib/tasks folder as geocode_my_data.rake
To run:
rake geocode:all CLASS=YourModel
Works great!
namespace :geocode_my_data do
desc "Geocode all objects without coordinates."
task :all => :environment do
class_name = ENV['CLASS'] || ENV['class']
sleep_timer = ENV['SLEEP'] || ENV['sleep']
raise "Please specify a CLASS (model)" unless class_name
klass = class_from_string(class_name)
klass.not_geocoded.find_each(batch_size: 100) do |obj|
obj.geocode; obj.save
sleep(sleep_timer.to_f) unless sleep_timer.nil?
end
end
end
##
# Get a class object from the string given in the shell environment.
# Similar to ActiveSupport's +constantize+ method.
#
def class_from_string(class_name)
parts = class_name.split("::")
constant = Object
parts.each do |part|
constant = constant.const_get(part)
end
constant
end
I am writing a Ruby on Rails application which has a Rake task that can parse a CSV file.
Here is the code:
desc "Import Channels into DB\n Usage: rake channel_import"
task :import_channels, :path_to_channel_list do |t, args|
require "#{Rails.root}/app/models/channel"
require "csv"
filePath = args.path_to_channel_list
puts "Filepath received = #{filePath}"
csv = CSV.read("#{filePath}", :encoding => 'windows-1251:utf-8')
csv.each_with_index do |row, i|
if [0].include?(i)
puts "Skipping over row #{i}"
next
end
if(row.nil?)
puts "row[#{i}] was nil"
else
channelName = nil
classif = nil
owner = nil
channelName = row[0].force_encoding('UTF-8')
classif = row[1].force_encoding('UTF-8')
owner = row[2].force_encoding('UTF-8')
if (channelName.nil?)
puts "Channel name for row #{i} was nil"
#add entry to Log file or errors database
next #skip this row of the csv file and go to next row
else
channel_hash = Hash.new("name" =>"#{channelName}", "classification" => "#{classif}", "owner" => "#{owner}" )
end
puts "\nChannel Name = #{channelName}\nClassification = #{classif}\n Ownership = #{owner}"
#If channel name exists in the Database, update it
xisting_channel = nil
xisting_channel = Channel.find_by channel_name: '#{channelName}'
if(xisting_channel.nil?)
#create a new channel
#new_channel = Channel.create(channel_hash)
puts "Inserted....#{#new_channel.inspect}"
else
#update existing channel
Channel.update(xisting_channel.id, :classification => "#{classif}", :ownership => "#{owner}" )
puts "Updated...."
puts "channel_hash = #{channel_hash.inspect} "
end#end if/else
end#end if/else
end #end CSV.each
end
When I run this code I get the following error message:
MRMIOMP0903:am AM$ rake import_channels[/XXXXXXXX/Channellist.csv]
Filepath received = /XXXXXXX/Channellist.csv
Skipping over row 0
Channel Name = APTN HD+
Classification = Specialty
Ownership = Aboriginal Peoples Television Network
rake aborted!
ActiveRecord::ConnectionNotEstablished
I tried to create a Channel object using IRB and it worked just fine. The DB is created and I'm seeing it using MySQL WorkBench. All tables are there, however, I am unable to create the Channel object from the Rake task.
My hypothesis is, perhaps outside of a certain folder/hierarchy the app cannot access the ActiveRecord::Base class or something like this.
Any suggestions on how to make this work?
UPDATE:
BAsed on the answer by Phillip Hallstrom
I changed the top line to load the environment
task :import_channels => :environment do|t, args|
Then tried rake import_channels and got this error:
rake aborted!
undefined method `safe_constantize' for #<Hash:0x007fbeacd89920>
You need to load the environment prior to running your Rake task. I'm not familiar with your multiple task name options there, but for a simple example, you'd want this:
task : import_channels => :environment do