延迟的ActionMailer无法提供多个收件人

时间:2013-12-19 15:54:34

标签: ruby-on-rails actionmailer sidekiq

我有一个像这样的邮件程序

class Mailer < ActionMailer::Base
  def newsletter_scheduler()
    recipients = User.all.to_a
    Mailer.delay_for(certain_time.days).newsletter(recipients)
  end

  def newsletter(recipients)
    recipients.each do |user|
      Logger.log("sending newsletter to #{user.email}"
      mail(
        to: user.email,
        subject: "What's hot last week",
      ).deliver
  end
end

我不是在寻找替代方案来实现这个...... 问题是,这只是将简报发送给最后一个收件人而且是多次 例如,在specs

it 'sends newsletter to all users' do
  Mailer.newsletter_scheduler()
  newsletters = ActionMailer::Base.deliveries

  newsletters.each { |nl| p nl.to }
end

我明白了(注意:我有5个用户)

["josh@haley.org"]
["josh@haley.org"]
["josh@haley.org"]
["josh@haley.org"]
["josh@haley.org"]

任何人都可以告诉我为什么在记录器显示以下内容时发生这种情况

sending newsletter to gertrude@gleasonlittle.biz
sending newsletter to bell@cormier.org
sending newsletter to alexa_sanford@rosenbaum.name
sending newsletter to hillard@mcclure.org
sending newsletter to josh@haley.org

[编辑] 以下代码与上面的代码具有相同的效果

class Newsletter
  def self.schedule
    recipients = User.all.map { |u| u.id }
    Mailer.delay_for(certain_time.days).newsletter(recipients)
  end
end

class Mailer < ActionMailer::Base
  def newsletter(recipients)
    recipients.each do |id|
      user = User.find(id)
      Logger.log("sending newsletter to #{user.email}"
      mail(
        to: user.email,
        subject: "What's hot last week",
      )
  end
end

Newsletter.schedule() #produces the same results in the specs

1 个答案:

答案 0 :(得分:2)

您的代码也提出了另一个问题。我在上面的代码中向您展示了邮件操作之外的#deliver

考虑拆分代码

class NewsletterScheduler
  def self.execute
    User.all.each do |user|
      Mailer.delay_for(certain_time.days).newsletter(user)
    end
  end
end

class Mailer < ActionMailer::Base
  def newsletter(user)
    Logger.log("sending newsletter to #{user.email}"
    mail(to: user.email, subject: "What's hot last week")
  end
end

NewsletterScheduler.execute

重要警告:您绝不应将复杂对象作为参数传递给队列。相反,始终传递参考。

在你的情况下改变

def newsletter(recipients)

接受一组ID而不是User对象数组。原因是对象很复杂,内部状态可能会发生变化,特别是如果它们存储在数据库中。此外,序列化原始值比序列化复杂对象更有效。

class NewsletterScheduler
  def self.execute
    User.all.each do |user|
      Mailer.delay_for(certain_time.days).newsletter(user_id)
    end
  end
end

class Mailer < ActionMailer::Base
  def newsletter(user_id)
    user = User.find(user_id)
    Logger.log("sending newsletter to #{user.email}"
    mail(to: user.email, subject: "What's hot last week")
  end
end