Rails Custom Rake Task no method error - ruby-on-rails

I am trying to set up a custom rake task for a Rails app that checks to see if your location is within a certain area with street cleaning restrictions. If it is, you can click a button "Remind Me" that will save the user id and restriction id to a reminder table.
I have the Rufus gem running the rake task every 15 minutes.
What I then want is the rake task to check the current time and day with the day and start time that corresponds with the restriction id, and if it is within 30 minutes, it should email the user to move their car.
When I run my current code below, I get this error:
rake aborted!
undefined method `reminders' for # <ActiveRecord::Relation::ActiveRecord_Relation_Day:0x007fb38c3274f8>
/Users/m/WDI/park_pointer/lib/tasks/reminder.rake:11:in `block (2 levels) in <top (required)>'
Tasks: TOP => reminder:mail_users
Here's my entire project: https://github.com/mnicole/park_pointer
But the code for the rake task is:
namespace :reminder do
desc "REMINDER"
task :mail_users => :environment do
time = Time.new
t = Time.now
today = Day.where(:id => time.wday + 1) #returns 0 for sunday, etc
#reminders = today.reminders
#reminders.each do |reminder|
#reminder = reminder
reminder_time_in_mins = restriction.start_time.hour * 60
current_time_in_mins = (Time.now.hour * 60) + Time.now.min
# last_time_in_mins = record.last.hour * 60 + record.last.min
if current_time_in_mins > (reminder_time_in_mins - 30)
#user = User.find(reminder.user_id.last)
UserMailer.reminder_email(user_id).deliver!
end
end
end
end
I THINK I'm almost there, but I've been working on this for a few months and am kind of at a loss about the next step.
Thanks in advance!!
-Michele

The problem is with this line:
today = Day.where(:id => time.wday + 1)
This isn't returning records, it's returning an ActiveRecord::Relation, which just means that the query hasn't been evaluated yet. (It does this so you can chain together filters and it only gets evaluated to SQL when you iterate over it.
Without knowing what your Day model looks like, I think what you want is this:
today = Day.where(:id => time.wday + 1).first
This will return the first result, or nil if there were no results. Then if today is non nil, it will have the reminders method.

Related

Rails: How to display data obtained from a background task in the home screen?

I have this code to scrape website ranking of http://example.com/ from Alexa
In lib/recurring.rb i have
module Recurring
class MyTask
include Delayed::RecurringJob
run_every 1.day
run_at '12:00pm'
timezone 'UTC'
def perform
url = "http://alexa.com/siteinfo/example.com"
doc = Nokogiri::HTML(open(url))
#rank = doc.at_css("strong.metrics-data.align-vmiddle").text
end
end
end
I have a raketask to execute this in lib/tasks/my_task.rake
namespace :recurring do
desc "Get website rank everyday at 12:00 OM UTC"
task init: :environment do
#Delete any previously-scheduled recurring jobs
Delayed::Job.where('(handler LIKE ?)', '--- !ruby/object:Recurring::%').destroy_all
Recurring::MyTask.schedule!
end
end
when I run
$ rake recurring:init
the task is executed everyday at 12:00 utc and I have the website rank in #rank (line number 10 recurring.rb).
But how can I display this data in my index page? I am new to background processing. Any help much appreciated.
Instance variables are in-memory and are not shared between your rake task and the server. So to pass data from one to the other you need persistence. The database is the standard choice but you could hypothetically use the filesystem, Redis, etc. as well.
Since you added :environment to your task you have access to your models (without it, the task is like a standalone Ruby script).
For example:
rails g model SiteRanking rank:string
rake db:migrate
# in rake task
SiteRanking.create(rank: #rank)
# in controller
#rank = SiteRanking.last.try(:rank) # will be nil if no record exists

ActiveRecord::AssociationTypeMismatch gotNilClass

I am a beginner programmer in Ruby and Ruby on Rails , I'm trying to run a rake command in my task , but when I do the following happens:
rake daily_tasks:process_api
rake aborted!
ActiveRecord::AssociationTypeMismatch: Estado(#47392639701120) expected, got NilClass(#47392580444120)
/home/thiagoamaralr/Desktop/proponente-master-4f8a3b2ddb02a90b2c173cf31383505018d02dd/app/services/create_programa_api.rb:21:in `call'
/home/thiagoamaralr/Desktop/proponente-master-74f8a3b2ddb02a90b2c173cf31383505018d02dd/lib/tasks/daily_tasks.rake:7:in `block (3 levels) in <top (required)>'
/home/thiagoamaralr/Desktop/proponente-master-74f8a3b2ddb02a90b2c173cf31383505018d02dd/lib/tasks/daily_tasks.rake:5:in `each'
/home/thiagoamaralr/Desktop/proponente-master-74f8a3b2ddb02a90b2c173cf31383505018d02dd/lib/tasks/daily_tasks.rake:5:in `block (2 levels) in <top (required)>'
Tasks: TOP => daily_tasks:process_api
(See full trace by running task with --trace)
Follow the task I'm trying to run:
namespace :daily_tasks do
desc "Process the day to day tasks"
task process_api: :environment do
SiconvApi::Programa.find.each do |programa|
if programa.data_inicio_recebimento_propostas && (programa.data_inicio_recebimento_propostas.to_date >= Date.parse("2015/06/01"))
CreateProgramaApi.call(SiconvApi::Serializers::Programa.new(programa))
end
end
end
end
And this is content create_programa_api.rb:
class CreateProgramaApi
def self.call(programa_api)
params = programa_api.to_h
params[:orgao] = Orgao.where("lower(name) = ?", programa_api[:orgao][:nome].mb_chars.downcase).first_or_create(name: programa_api[:orgao][:nome])
params[:orgao_vinculado] = Orgao.where("lower(name) = ?", programa_api[:orgao_vinculado][:nome].mb_chars.downcase).first_or_create(name: programa_api[:orgao_vinculado][:nome])
params[:orgao_executor] = Orgao.where("lower(name) = ?", programa_api[:orgao_executor][:nome].mb_chars.downcase).first_or_create(name: programa_api[:orgao_executor][:nome])
params[:estados] = []
if programa_api[:estados].size == 27
params[:estados] << Estado.find_by(sigla: 'Todos')
else
programa_api[:estados].each do |e|
params[:estados] << Estado.find_by(sigla: e)
end
end
params[:atendes] = [Atende.where("lower(name) = ?", programa_api[:atende_a].mb_chars.downcase).first_or_create(name: programa_api[:atende_a])] if programa_api[:atende_a]
params.delete(:atende_a)
programa = Programa.find_by(codigo: programa_api[:codigo])
if programa
programa.update(params)
else
Programa.create! params
end
end
end
Thanks for your attention!
You have nil object in params[:estados], and Rails can't save this association.
Easiest way to remove them is to call params[:estados].compact! after line 14
This block of code is your problem:
params[:estados] = []
if programa_api[:estados].size == 27
params[:estados] << Estado.find_by(sigla: 'Todos')
else
programa_api[:estados].each do |e|
params[:estados] << Estado.find_by(sigla: e)
end
end
If no record is found, the #find_by returns nil. This is why you are getting the error:
ActiveRecord::AssociationTypeMismatch: Estado(#47392639701120) expected, got NilClass
When calling Programa.create!(params).
One solution would be to call params[:estados].compact! after the if statement (this is using Array#compact! to remove any nil values).
Or, you could instead write that section of code like this:
params[:estados] = Estadio.where(
sigla: (programa_api[:estados].size == 27 ? 'Todos' : programa_api[:estados])
)
With this code, there is no longer a need to call compact! since we already end up with an empty array if no records are found (i.e. there are no nil values).
Note that the behaviour here isn't quite the same - what happens if there are multiple Estado records with the sigla equal to one of programa_api[:estados] or 'Todos'? Previously you were only fetching the "first" such record, whereas now you'd be fetching all of them. This may not be an issue (or may even be the correct behaviour!!) - it's just something to be aware of, at least.

How to trigger a rake task using whenever in Rails

I am writing a Rake task. I want to trigger it every last sunday of every month at 11 pm.
How can I schedule this using the Whenever gem in Ruby on Rails?
I have my rake task in the following location: app/lib/tasks/my_task.rake
task :create_entries => :environment do
puts "Hello"
end
I don't think there's a rule for "last x day of the month" but you can always put an extra if test inside the block:
every :sunday, :at => '11pm' do
#if the month is different a week from now, we must be in the last
#sunday of the month
if Time.now.month != 1.week.from_now.month
rake "my:rake:task"
end
end
So, this scheduled code will run every sunday, but it will only go on to call the rake task if the time meets the further conditions.

delayed_job dies with out error - no attempt has been made

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

calling a class method from scheduler.rake in ruby

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)

Resources