ruby-on-railsrubyruby-on-rails-5delayed-jobruby-on-rails-4.2

Rails 5 upgrade broke delayed tasks


I upgraded my Rails application from Rails 4.2 to Rails 5.0 and now a lot of my delayed jobs which were created pre-upgrade are breaking. I get the following error:

undefined method 'game_completion_feedback' for ConfirmationMailer:Class

Even though I have the method defined in the ConfirmationMailer class and nothing was changed in that class or where it's being invoked from while upgrading.

On doing a YAML.load_dj I get the following error:

ArgumentError: undefined class/module ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer
from <path>/.rvm/rubies/ruby-2.2.5/lib/ruby/2.2.0/psych/class_loader.rb:53:in `path2class'
Caused by NameError: uninitialized constant 
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer
from <path>/.rvm/gems/ruby-2.2.5/gems/activesupport-5.0.7.1/lib/active_support/inflector/methods.rb:283:in `const_get' 

It looks like it broke because something changed during the Rails 4.2 to Rails 5.0 upgrade.

I found online that running Rails.cache.clear can help fix this issue but my tmp folder in the production environment is empty so running Rails.cache.clear just throws an error as:

No such file or directory @ dir_initialize - /var/app/current/tmp/cache/

Is there any way that I can make these old delayed jobs still work in Rails 5.0 or do I just have to recreate all of them individually?

My ConfirmationMailer class:

class ConfirmationMailer < ApplicationMailer
  def game_completion_feedback(user, date, feedback)
    @user     = user
    @date     = format_time(date.to_time)
    @feedback = feedback

    mail(to: user.email, subject: 'Game Completed')
  end
end

And I call that function as:

def send_feedback_to_client
  ConfirmationMailer.delay.game_completion_feedback(user, date, feedback)
end

This is coming up in other situations as well where I am calling a Struct such as:

class RemindersForGame < Struct.new(:gamer_email, :leader_email, :start)
  def perform
    ConfirmationMailer.game_reminder_email_gamer(gamer_email, leader_email, start).deliver_now
    ConfirmationMailer.game_reminder_email_leader(gamer_email, leader_email, start).deliver_now
  end
end

And I call this struct as:

def create_reminder_email(start)
  reminders = Delayed::Job.enqueue RemindersForGame.new(client.user, coach, start),
                                 run_at: start - 2.day,
                                 queue: 'game_reminder'

self.reminders_job_id = reminders.id

end

The game_reminder_email_gamer and game_reminder_email_leader are defined as the exact same way as the other method in that class and I didn't change anything related to how it's being called.


Solution

  • For versions < Rails 4.2: ConfirmationMailer.delay.game_completion_feedback(user, date, feedback)

    For versions > Rails 4.2: ConfirmationMailer.game_completion_feedback(user, date, feedback).deliver_later

    Please try using this and let us know if it solves the problem.

    Also, when passing variables to your Mailer class, using the with() method will create instance variables for you to use in the mailer instance. For example:

    ConfirmationMailer.with(u: user, d: date, f: feedback).game_completion_feedback.deliver_later
    

    Would then create @u, @d, @f as instance variables for use in your Mailer instance.

    I'm not suggesting you name your variables as single characters :) But show that you don't need the positional arguments.