5

I'm trying to send mail in a Rails 3 application using collectiveidea's delayed_job. If I try to send mail regularly (.deliver) it works fine, but as soon as I switch to delayed job, things fall to pieces.

The standard error I get in the delayed_job mysql table is:

{undefined method `name' for nil:NilClass...

where 'name' is the first argument in the mailer's view (@contact.name). This works fine if I take delayed_job out again.

If I remove all references to @contact in the view, I get

{A sender (Return-Path, Sender or From) required to send a message

In short, it doesn't seem to be understanding any arguments at all.

All relevant code below - if anyone has any suggestions for this it would be very appreciated

CONTROLLER

  def sendmail
    @contact = Contact.new(params[:contact])
    if @contact.save
      ContactMailer.delay.contact_mail(@contact)
      flash[:notice] = 'Your message has been successfully sent'
      redirect_to root_path
    else
      render :action => 'index'
    end
  end

MAILER:

class ContactMailer < ActionMailer::Base
  default :from => "my@email.address"  

  def contact_mail(contact)
    @contact = contact
    mail(:to => 'my@email.address', :subject => 'Contact Form Query', :from => 'my@email.address', :content_type => 'text/plain')
  end
  handle_asynchronously :contact_mail, :run_at => Proc.new { 2.seconds.from_now }
end

MAILER VIEW:

You have received a new query:
-----------------------------------

<%= @contact.name %>

<%= @contact.business %>

<%= @contact.phone %>

-----------------------
<%= @contact.message %>
-----------------------

INITIALIZER:

Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.max_run_time = 5.weeks

And finally, the full error message:

    {undefined method `name' for nil:NilClass

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0/lib/active_support/whiny_nil.rb:48:in `method_missing'

/Users/john/Websites/Rails/InDevelopment/connectted/app/views/contact_mailer/contact_mail.html.erb:4:in `_app_views_contact_mailer_contact_mail_html_erb___3386534441642202773_2166008980__4301703149293725172'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/action_view/template.rb:135:in `block in render'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0/lib/active_support/notifications.rb:54:in `instrument'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/action_view/template.rb:127:in `render'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/action_view/render/rendering.rb:59:in `block in _render_template'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0/lib/active_support/notifications.rb:52:in `block in instrument'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0/lib/active_support/notifications/instrumenter.rb:21:in `instrument'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/activesupport-3.0.0/lib/active_support/notifications.rb:52:in `instrument'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/action_view/render/rendering.rb:56:in `_render_template'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/action_view/render/rendering.rb:26:in `render'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/abstract_controller/rendering.rb:114:in `_render_template'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/abstract_controller/rendering.rb:108:in `render_to_body'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/abstract_controller/rendering.rb:101:in `render_to_string'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionpack-3.0.0/lib/abstract_controller/rendering.rb:92:in `render'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/deprecated_api.rb:111:in `render'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/old_api.rb:210:in `block in create_parts'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/old_api.rb:208:in `each'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/old_api.rb:208:in `create_parts'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/deprecated_api.rb:143:in `create_parts'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/old_api.rb:77:in `process'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/base.rb:446:in `process'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/base.rb:441:in `initialize'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/base.rb:425:in `new'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/actionmailer-3.0.0/lib/action_mailer/base.rb:425:in `method_missing'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/performable_mailer.rb:6:in `perform'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/backend/base.rb:83:in `invoke_job'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:119:in `block (2 levels) in run'

/Users/john/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/timeout.rb:57:in `timeout'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed
/worker.rb:119:in `block in run'

/Users/john/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/benchmark.rb:309:in `realtime'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:118:in `run'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:176:in `reserve_and_run_one_job'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:103:in `block in work_off'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:102:in `times'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:102:in `work_off'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:77:in `block (2 levels) in start'

/Users/john/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/benchmark.rb:309:in `realtime'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:76:in `block in start'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:73:in `loop'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/worker.rb:73:in `start'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/command.rb:100:in `run'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/command.rb:79:in `block in run_process'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/application.rb:250:in `call'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/application.rb:250:in `block in start_proc'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/daemonize.rb:199:in `call'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/daemonize.rb:199:in `call_as_daemon'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/application.rb:254:in `start_proc'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/application.rb:294:in `start'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/controller.rb:70:in `run'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons.rb:193:in `block in run_proc'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/cmdline.rb:112:in `call'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons/cmdline.rb:112:in `catch_exceptions'

/Users/john/.rvm/gems/ruby-1.9.2-p0/gems/daemons-1.1.0/lib/daemons.rb:192:in `run_proc'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/command.rb:78:in `run_process'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/command.rb:72:in `block in daemonize'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/command.rb:70:in `times'

/Users/john/.rvm/gems/ruby-1.9.2-p0/bundler/gems/delayed_job-c933ffcd776a/lib/delayed/command.rb:70:in `daemonize'
script/delayed_job:5:in `<main>' |
PlankTon
  • 12,443
  • 16
  • 84
  • 153
  • 1
    I'm assuming none of the answers below solved your problem? Did you ever figure this out? I'm having a similar issue, except in my case my jobs are "succeeding", but nothing is actually happening. I added logging to the first line and I got nothing. I'm suspecting it's related to either a) rvm (my app uses 1.9.2, my system ruby is 1.8.7) or b) mongoid somehow (although it's finding the jobs just fine). I'm going to investigate the rvm thing, although I'm really not sure how to get the daemon to run under 1.9.2 at this point. – Brad Apr 03 '11 at 05:26
  • Hi Brad - unfortunately no answer was ever found. I think I resorted to manually cronning out mails from the server manually, which isn't really an ideal solution. – PlankTon Apr 03 '11 at 22:31
  • Bummer. I haven't figured it out either. In my case if I create the job in the rails console and then call "Delayed::Worker.new.start", it will work. But if I run "script/delayed_job start" in the application's root directory in another terminal, I get absolutely nothing. It finds the jobs, the log says "1 job found, 0 failed", but nothing has happened. I have no idea how to even debug this, since the worker starts in another process in that case, but it must be related to that process running in a different environment in some way. – Brad Apr 04 '11 at 04:16
  • *nods* I spent about two full days on it with no joy...wish I could offer more help. – PlankTon Apr 04 '11 at 05:13
  • Found an ugly workaround. Use an ActiveRecord model instead of a regular class. Good luck... – cider Feb 10 '13 at 09:33

5 Answers5

11

The issue is with the code in your mailer taking the object instead of the objects id:

def contact_mail(contact)
    @contact = contact
    mail(:to => 'my@email.address', :subject => 'Contact Form Query', :from => 'my@email.address', :content_type => 'text/plain')
end

You should change that to this:

def contact_mail(contact_id)
    @contact = Contact.find(contact_id)
    mail(:to => 'my@email.address', :subject => 'Contact Form Query', :from => 'my@email.address', :content_type => 'text/plain')
end

Never pass the actual objects to your mailer. Simply pass the id's and retrieve them upon processing.

Adam
  • 436
  • 4
  • 10
1

I had this same problem, and fixed it by moving all the attributes into instance variables. So, in the view:

<%= @contact.name %>
<%= @contact.business %>
<%= @contact.phone %>

becomes:

<%= @name %>
<%= @business %>
<%= @phone %>

and I just looked up the instance variables in the mailer method. So, in the mailer:

def contact_mail(contact)
    @contact = contact
    mail(:to => 'my@email.address', :subject => 'Contact Form Query', :from => 'my@email.address', :content_type => 'text/plain')
end

becomes:

def contact_mail(contact)
    @name = contact.name
    @business = contact.business
    @phone = contact.phone
    mail(:to => 'my@email.address', :subject => 'Contact Form Query', :from => 'my@email.address', :content_type => 'text/plain')
end
Matt Sonic
  • 11
  • 1
0

Why is it not working? Not sure, I imagine it has to do with some ActionMailer voodoo.

How to get it working? Abstract out the delayed job pieces into another class. Have the method that is delayed do nothing more than send them email; meaning that the rendering of the email is done in real time, but the sending of it is delayed. This should get around your problem and accomplish the asynchronous sending of emails.

Aaron Scruggs
  • 712
  • 1
  • 4
  • 10
0

Hey this might be far off, but you're not sending any params to your MAILER. Here's a copy of my referred_email.rb I keep in my lib/ dir. I call it with delayed_job:

#my controller
Delayed::Job.enqueue ReferredEmail.new(params[:subject], params[:editor1])

#Reffered_Email.rb

class ReferredEmail < Struct.new(:subject, :editor1)
  def perform
    (CardReferral.all.map(&:email) - CardSignup.all.map(&:email)).each do |cf|
      @cf = CardReferral.find_by_email(cf)
      Notifier.deliver_referred_magic_email(User.find(@cf.user_id), @cf.email, @cf.name, @cf.message, subject, editor1)
    end
  end
end
Trip
  • 26,756
  • 46
  • 158
  • 277
0

It seems like you are using both:

  ContactMailer.delay.contact_mail(@contact)

and

  handle_asynchronously :contact_mail, :run_at => Proc.new { 2.seconds.from_now }

which you should only do one or the other. Try removing the handle_asynchronously and see if that fixes the problem.

christophercotton
  • 5,829
  • 2
  • 34
  • 49