I have used sidekiq
and redis-server
to send email in background..
Problem: Its ok when used sync method to send email. i.e.
in applicants_controller.rb
UserMailer.notify_applicant_assignment(current_assigned_user.id, applicant, workflow_step).deliver
However, when I use delay
method to send email i.e.
in applicants_controller.rb
UserMailer.delay.notify_applicant_assignment(current_assigned_user.id, applicant, workflow_step)
I get the following error undefined method 'background_color' for nil:NilClass
in /layouts/user_mailer.html.erb:17:
Code inside mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
include Sidekiq::Worker
default from: CommonConstants::DO_NOT_REPLY_ADDRESS
layout 'user_mailer'
def notify_applicant_assignment(user_id, applicant_id, workflow_step_id)
@user = User.find(user_id)
@organization = @user.organization
@applicant = Applicant.find(applicant_id)
@url = root_url + 'applicants/' + @applicant.id.to_s
@workflow_step = WorkflowStep.find(workflow_step_id)
mail(to: @user.email, subject: 'Applicant Assigned.')
end
end
Code inside layouts/user_mailer.html.erb
<body style="background:#f4f4f4;">
<table width="100%" bgcolor="<%= @organization.background_color %>" cellpadding="0" cellspacing="0">
<tr>
<td>
<table align="center" width="730" cellpadding="0" cellspacing="0" >
Error I got in sidekiq console
2015-03-24T08:58:14Z 5595 TID-cjors WARN: {"retry"=>true, "queue"=>"default", "class"=>"Sidekiq::Extensions::DelayedMailer", "args"=>["---\n- !ruby/class 'UserMailer'\n- :notify_applicant_assignment\n- - 4\n - '9'\n - '9'\n"], "jid"=>"4421abf04e7e6864c7ee9fd8", "enqueued_at"=>1427187124.323067, "error_message"=>"undefined method `background_color' for nil:NilClass", "error_class"=>"ActionView::Template::Error", "failed_at"=>1427187124.3466575, "retry_count"=>4, "retried_at"=>1427187494.9246943}
2015-03-24T08:58:14Z 5595 TID-cjors WARN: undefined method `background_color' for nil:NilClass
2015-03-24T08:58:14Z 5595 TID-cjors WARN: /home/leapfrog/projects/ATS/app/views/layouts/user_mailer.html.erb:17:in `_app_views_layouts_user_mailer_html_erb__235114594899105140_70586860'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/actionpack-4.0.4/lib/action_view/template.rb:143:in `block in render'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/activesupport-4.0.4/lib/active_support/notifications.rb:161:in `instrument'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/actionpack-4.0.4/lib/action_view/template.rb:141:in `render'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/actionpack-4.0.4/lib/action_view/renderer/template_renderer.rb:61:in `render_with_layout'
/
It's very possible that the delay extension work differently then you would expect. They are different that the regular async job.
In the documentation, it is clearly stated that:
I strongly recommend avoiding delaying methods on instances. This stores object state in Redis which can get out of date, causing stale data problems.
I wouldn't be surprised if the delay extension stores the unrendered template and the mail parameters (subject, to, from, etc') rather then calling the method itself for an outdated instance.
Also, please notice that notify_applicant_assignment
isn't defined as a class method (it looks like an instance method), although the Sidekiq documentation states that delay should be applied to class methods.
Any class method can be delayed via the same methods as above:
I would recommend making the notify_applicant_assignment
a class method and trying again (notice the self in def self.notify_applicant_assignment
vs. def notify_applicant_assignment
).
class UserMailer < ActionMailer::Base
include Sidekiq::Worker
default from: CommonConstants::DO_NOT_REPLY_ADDRESS
layout 'user_mailer'
def self.notify_applicant_assignment(user_id, applicant_id, workflow_step_id)
@user = User.find(user_id)
@organization = @user.organization
@applicant = Applicant.find(applicant_id)
@url = root_url + 'applicants/' + @applicant.id.to_s
@workflow_step = WorkflowStep.find(workflow_step_id)
mail(to: @user.email, subject: 'Applicant Assigned.')
end
end
Alternatively, I would recommend also using the standard async engine in applicants_controller.rb
:
UserMailer.notify_applicant_assignment_async(current_assigned_user.id, applicant, workflow_step)
Please let me know how it goes, so I can research some more if there's still a need.
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With