Rails - 异步发送带有delayed_job的所有电子邮件

时间:2014-02-04 15:08:01

标签: ruby-on-rails ruby-on-rails-3 asynchronous devise actionmailer

我正在使用delayed_job,我对它非常满意(特别是workless扩展名)。

但我想设置我的应用中的所有邮件是异步发送的。

确实,为邮寄者提供的解决方案

# without delayed_job
Notifier.signup(@user).deliver

# with delayed_job
Notifier.delay.signup(@user)

不适合我,因为:

  • 不易维护
  • 从宝石发送的邮件不会异步发送(devisemailboxer

我可以使用这种扩展程序https://github.com/mhfs/devise-async,但我宁愿一次找出整个应用程序的解决方案。

我无法扩展ActionMailer以覆盖.deliver方法(例如此处https://stackoverflow.com/a/4316543/1620081,但它已有4年历史,就像我在该主题上发现的几乎所有文档一样)?

我正在使用带有activerecord的Ruby 1.9和Rails 3.2。

感谢您的支持

2 个答案:

答案 0 :(得分:0)

一个简单的解决方案是在Notifier对象上编写实用程序方法,如下所示:

class Notifier

  def self.deliver(message_type, *args)
    self.delay.send(message_type, *args)
  end

end

按如下方式发送注册电子邮件:

Notifier.deliver(:signup, @user)

实用程序方法提供了一个单点,如果需要,您可以使用resque或sidekiq解决方案替换延迟作业。

答案 1 :(得分:0)

如果您已设置ActiveJob并且并发库已完成设置documentation here。最简单的解决方案是覆盖与交易邮件相关的设备 send_devise_notification 实例方法,例如{{ 3}}

class User < ApplicationRecord
  # whatever association you have here
  devise :database_authenticatable, :confirmable
  after_commit :send_pending_devise_notifications
  # whatever methods you have here

 protected
  def send_devise_notification(notification, *args)
    if new_record? || changed?
      pending_devise_notifications << [notification, args]
    else
      render_and_send_devise_message(notification, *args)
    end
  end

  private

  def send_pending_devise_notifications
    pending_devise_notifications.each do |notification, args|
      render_and_send_devise_message(notification, *args)
    end

    pending_devise_notifications.clear
  end

  def pending_devise_notifications
    @pending_devise_notifications ||= []
  end

  def render_and_send_devise_message(notification, *args)
    message = devise_mailer.send(notification, self, *args)

    # Deliver later with Active Job's `deliver_later`
    if message.respond_to?(:deliver_later)
      message.deliver_later
    # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
    elsif message.respond_to?(:deliver_now)
      message.deliver_now
    else
      message.deliver
    end
  end

end