I'm a Rails newbie, so please forgive any ignorance on my part. The issue I'm having is that I have a Resque job setup to send an email. I have the job running, but it produces an error:
Unable to deliver email [send_daily_digest_email]: wrong number of arguments (given 2, expected 0)
I get this same error when I try to test the mailer from console...
TicketMailer.send_daily_digest_email("emailaddress#domain.com").deliver_now
Here is the mailer code:
class TicketMailer < ActionMailer::Base
layout 'mailer'
include Resque::Mailer
default :from => 'test <test#ignore.com>'
def send_daily_digest_email(email)
mail(:to => email, :subject => 'test')
end
end
What am I doing wrong? Where should I look to figure this out? Thanks!
As noted in the comments, the issue was due to Rails 5 not being fully supported in the current release of the resque-mailer gem. Support is built in now, but I had to pull from master on the repo:
gem "resque_mailer", :git => "https://github.com/zapnap/resque_mailer.git"
Related
I am on Heroku with a custom domain, and I have the Redis add-on. I need help understanding how to create a background worker for email notifications. Users can inbox message each other, and I would like to send a email notification to the user for each new message received. I have the notifications working in development, but I am not good with creating background jobs which is required for Heroku, otherwise the server would timeout.
Messages Controller:
def create
#recipient = User.find(params[:user])
current_user.send_message(#recipient, params[:body], params[:subject])
flash[:notice] = "Message has been sent!"
if request.xhr?
render :json => {:notice => flash[:notice]}
else
redirect_to :conversations
end
end
User model:
def mailboxer_email(object)
if self.no_email
email
else
nil
end
end
Mailboxer.rb:
Mailboxer.setup do |config|
#Configures if you applications uses or no the email sending for Notifications and Messages
config.uses_emails = false
#Configures the default from for the email sent for Messages and Notifications of Mailboxer
config.default_from = "no-reply#domain.com"
#Configures the methods needed by mailboxer
config.email_method = :mailboxer_email
config.name_method = :name
#Configures if you use or not a search engine and which one are you using
#Supported enignes: [:solr,:sphinx]
config.search_enabled = false
config.search_engine = :sphinx
end
Sidekiq is definitely the way to go with Heroku. I don't think mailboxer supports background configuration out of the box. Thankfully, it's still really easy with sidekiq's queueing process.
Add gem 'sidekiq' to your gemfile and run bundle.
Create a worker file app/workers/message_worker.rb.
class MessageWorker
include Sidekiq::Worker
def perform(sender_id, recipient_id, body, subject)
sender = User.find(sender_id)
recipient = User.find(recipient_id)
sender.send_message(recipient, body, subject)
end
end
Update your Controller to Queue Up the Worker
Remove: current_user.send_message(#recipient, params[:body], params[:subject])
Add: MessageWorker.perform_async(current_user.id, #recipient.id, params[:body], params[:subject])
Note: You should never pass workers ActiveRecord objects. That's why I setup this method to pass the User ids and look them up in the worker's perform method, instead of the entire object.
Finally, restart your server and run bundle exec sidekiq. Now your app should be sending the email background.
When you deploy, you will need a separate dyno for the worker which should look like this: worker: bundle exec sidekiq. You will also need Heroku's redis add-on.
Sounds like a H21 Request Timeout:
An HTTP request took longer than 30 seconds to complete.
To create a background worker for this in RoR, you should grab Resque, a Redis-backed background queueing library for RoR. Here is a demo. Another demo. And another demo.
To learn more about using Resque in Heroku, you can also read the herokue article up here. Or this tutorial (it's an old one though). Another great tutorial.
There is also a resque_mailer gem that will speed things up for you.
gem install resque_mailer #or add it to your Gemfile & use bundler
It is fairly straightforward. Here is a snippet from a working demo by the author:
class Notifier < ActionMailer::Base
include Resque::Mailer
default :from => "from#example.com"
def test(data={})
data.symbolize_keys!
Rails.logger.info "sending test mail"
Rails.logger.info "params: #{data.keys.join(',')}"
Rails.logger.info ""
#subject = data[:subject] || "Testing mail"
mail(:to => "nap#localhost.local",
:subject => #subject)
end
end
doing Notifier.test.deliver will deliver the mail.
You can also consider using mail delivery services like SES.
Sidekiq is an option that you could consider. To get it working you can add something like RedisToGo, then configure an initializer for Redis. Then on Heroku you can add something like worker: bundle exec sidekiq ... to your Procfile.
https://github.com/mperham/sidekiq/wiki/Getting-Started
It also has a dashboard for monitoring.
https://github.com/mperham/sidekiq/wiki/Monitoring
My application was sending mails in background in development but recently i installed redis and resque to use resque along with resque-mailer and now nothing is working.Everytime i get a message RuntimeError Invalid delivery method :resque.I have been trying hard to figure out whats wrong because earlier i just included resque-mailer in user_mailer.rb and thats it,my mails were running but now i dont know what wrong i did.below are my relevant file AFTER INSTALLING REDIS using Railscasts for resque.I googled alot to find but many times i came across monkey patching devise but i dont think i need to do that as my mailers were working fine without worrying about devise.Using ruby 1.9.3 and rails 3.2
im getting same error when tried with sidekiq :(
my gemfile.
gem 'resque','1.19.0' ,:require => "resque/server"
gem 'resque_mailer'
my user_mailer.rb
class UserMailer < ActionMailer::Base
include Resque::Mailer
default from: "support#mywebsite.com"
def logged_in(user.id)
Rails.logger.info 'sending mail----------registeration mail----------'
#user=User.find(user_id)
p #user
###line number 19 is below
mail(:to => #user.email, :subject => " Hi #{#user.username},You logged-in just now ")
end
app/controllers/users/devise/sessions_controller.rb
##enqueue the mailer using resque and send mail asynchronously
###this was working earlier but now its not so i made use of railscasts above to use redis
###UserMailer.logged_in(resource.id).deliver
#user_id=resource.id
Resque.enqueue(UserMailerWorker,#user_id)
now the changes that i did using Railscasts and mail is not sending giving above error
my worker
class UserMailerWorker
#queue = :user_mailer_job_queue
def self.perform(user_id)
p 'usermailer worker sending logged in mail----'
p user_id
UserMailer.logged_in(user_id).deliver
end
end
backtrace error as seen in resque-web UI---
localhost.localdomain:8119 on mailer at just now
Retry or Remove
Class
UserMailer
Arguments
"logged_in"
7
Exception
RuntimeError
Error
Invalid delivery method :resque
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionmailer-3.2.0/lib/action_mailer/delivery_methods.rb:71:in `wrap_delivery_behavior'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionmailer-3.2.0/lib/action_mailer/delivery_methods.rb:83:in `wrap_delivery_behavior!'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionmailer-3.2.0/lib/action_mailer/base.rb:628:in `mail'
/mnt/hgfs/latest-master/latest/app/mailers/user_mailer.rb:19:in `logged_in'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionpack-3.2.0/lib/abstract_controller/base.rb:167:in `process_action'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionpack-3.2.0/lib/abstract_controller/base.rb:121:in `process'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionpack-3.2.0/lib/abstract_controller/rendering.rb:45:in `process'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionmailer-3.2.0/lib/action_mailer/base.rb:456:in `process'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/actionmailer-3.2.0/lib/action_mailer/base.rb:451:in `initialize'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/resque_mailer-2.2.6/lib/resque_mailer.rb:48:in `new'
/usr/local/rvm/gems/ruby-1.9.3-head#latest/gems/resque_mailer-2.2.6/lib/resque_mailer.rb:48:in `perform'
well after removing and resetting my application...i came to know why i was getting this error.its because i was not starting the resque job as well as redis.so after starting redis using redis-server and resque using bundle exec rake resque:work QUEUE='*'...my asynchronous mail started working without any problem just by including include Resque::Mailer
I'm trying to send emails using delayed job from my Rails 3.2 app on Heroku when someone fills out a form. I've been able to get the emails to send successfully through delayed job on my local development machine. I can also get the emails to send using delayed job if I run them manually through the console on Heroku. However, when someone submits a form which triggers the email, it will not send.
Here's my mailer:
class ClaimMailer < ActionMailer::Base
default from: "noreply#coatchex.com"
def patron(claim)
mail(:to => claim.email, :subject => I18n.t('mailers.claims.patron.subject'))
end
def coatchex(claim)
#claim = claim
mail(:to => 'claims#coatchex.com', :subject => I18n.t('mailers.claims.coatchex.subject'))
end
end
Here's my controller:
class ClaimsController < ApplicationController
layout 'basic'
def new
#claim = CoatChex::Forms::Claim.new
end
def create
#claim = CoatChex::Forms::Claim.new(params[:claim])
if #claim.valid?
ClaimMailer.delay.coatchex(#claim)
render :thank_you
else
render :new
end
end
end
Like I mentioned, If I run the following command through the Heroku console it queues the email up in delayed job and sends it just fine:
#claim = ...
ClaimMailer.delay.coatchex(#claim)
However, whenever I send it through the form, it does not trigger.
If I'm quick enough I can run Delayed::Job.count in the Heroku console and see a value of 1 before the job executes when submitting through the form. So I know delayed job is getting it. If I look at the worker logs using
heroku logs -p worker -t
I can see the job process getting logged when executing it manually but not when it goes through the form.
There are no failed jobs in the database.
Anybody run into anything like this before?
I had a similar problem. A good starting point was the information at https://devcenter.heroku.com/articles/delayed-job#debugging - specifically, running Delayed::Job.last.last_error on the Heroku console.
In my case, the error I was getting was Job failed to load: uninitialized constant Syck::Syck, which was fixed by adding psych to my gemfile. See Delayed_job: Job failed to load: uninitialized constant Syck::Syck and http://effectif.com/ruby-on-rails/syck-and-psych-yaml-parsers-on-heroku
You need to start the worker with the command
rake jobs:work
on your heroku rails console.
I've been trying to figure out how to send delayed mail using delayed_job with rails 3. I've tried pretty much every combination of feasible possibilities I can think of - I can get the mail to run in the background, I just can't get it to delay the sending to a future time. The delayed_jobs table in the db clears the tasks, the log says 'sent', the delayed_job task processor picks up the task & says sent without failure...but the mail is either:
sent immediately, or
simply doesn't arrive
if I try to send in the future.
If anyone could offer a bare-bones example of a rails 3 delayed_job that sends mail in the future, I'd be really appreciative. I'm sure lotsa folks do this so I suspect I'm missing something obvious. One (of countless) combinations I've tried below:
delayed_job: 2.1.2
rails: 3.0.3
actionmailer: 3.0.3
Controller:
class TestmailerController < ApplicationController
def index
Testmailer.delay.test_mail
end
end
Mailer:
class Testmailer < ActionMailer::Base
def test_mail
mail(:to => '(myemailaddress#removedforprivacy.com', :from => '(removedforprivacy)#gmail.com', :subject => 'Testing Delayed Job', :content_type => 'text/plain').deliver
end
handle_asynchronously :test_mail, :run_at => Proc.new { 2.minutes.from_now }
end
relevant mail part of config/environments/development.rb:
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = true
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "gmail.com",
:user_name => "(removedforprivacy)",
:password => "(removedforprivacy)",
:authentication => "plain",
:enable_starttls_auto => true
}
Job command:
rake jobs:work
I agree with andrea - I was having this exact problem, and after switching my local development database from sqlite to mysql, I can run code like
Emailer.delay({:run_at => 5.minutes.from_now}).welcome(#user)
and it sends the email 5 minutes later. Note that you might need a bigger delay than five minutes (in case of time zone weirdness) to be sure it is working.
I found in Rails 3 with mongoid that removing the handle_asynchronously line gets it to work. I was having all kinds of problems, and it appeared that delayed_job wasn't recognizing any objects within my Emailer class. Removing handle_asynchronously fixed it.
Both using the .delay method and setting handle_asynchronously :test_mail is redundant. Try removing the .delay method from your code. use simply
Testmailer.test_mail # without .deliver due to a delayed_job issue
However, I ran some test on your configuration and when using sqlite, run_at is simply ignored (do not know why), but when using mysql2 everything works fine.
I'm using the delayed_job gem here: https://github.com/collectiveidea/delayed_job
I have the following in an observer:
UserMailer.delay.msg_notification(record)
In user_mailer.rb
class UserMailer < ActionMailer::Base
...
def msg_notification(record)
mail(
:to => "#{record.user.email}",
:subject => "Notification"
)
end
..
end
But this errors with:
NoMethodError (undefined method `delay' for UserMailer:Class):
Any ideas? thanks
I've seen a problem like this on our Rails app (2.3.8, but the issue sounds the same). Basically, there are three ways to delay an action:
MyClass.delay.foo(arg)
Putting handle_asynchronously :foo in your class definition after the definition of foo
MyClass.send_later(:foo, arg)
For whatever reason, #3 was the only form that worked consistently across all our development machines. #1 died on our development server (Ubuntu); #2 on our designer's Mac. But #3 was fine.
Hope that helps!
Also check if you have restarted your server after the bundle install. That could be a issue too...