0

我正在运行问答服务。管理员可以做的一件事是将问题标记为离题。当他们这样做时,会向提出问题的人发送一封电子邮件,告诉他们他们的电子邮件偏离主题。

电子邮件通知通过delayed_job 发送:

QuestionMailer.delay.notify_asker_of_offtopic_flag question

但是,有时有人可能会不小心将问题标记为离题或改变主意。为了避免向最初询问它的人发送不正确的通知,我想创建一个短暂的延迟,并在邮件请求运行时评估问题是否仍然是题外话:

延迟致电邮寄者:

QuestionMailer.delay(run_at: Time.now + 3.minutes).notify_asker_of_offtopic_flag(question)

邮寄者:

class QuestionMailer
  ...
  def notify_asker_of_offtopic_flag question
     if question.offtopic?
       # do mailing
     end
  end
end

不幸的是,这并不是那么简单,因为该if块只会导致一个错误,然后导致 delay_job 一次又一次地重试该作业。

我现在正在尝试一些非常迂回的方法来达到同样的目的,但我真的很想找到一些方法来中止QuestionMailer操作而不触发错误。这可能吗?

4

2 回答 2

2

然后不要延迟邮寄。也许在您的 Question 类中延迟另一个类方法?传递问题的 id 并在该延迟方法中检查问题是否仍然是题外话,如果是,则同步发送电子邮件。

本质上,您的 notify_asker_of_offtopic_flag 可以移动到您的问题模型,然后邮件是同步的(我相信您会重命名您的方法)。

关于通过在核心的邮件操作本身中将 perform_deliveries 设置为 false 来防止传递的讨论正在进行,但我不是 100% 会在哪里或如何结束。

于 2012-07-26T19:24:39.103 回答
1

@Aditya 的回答基本上是正确的,但是我想将我的方法保留在 Mailer 对象上以保持整洁。这需要一些额外的技巧。

在可以延迟的邮件程序中创建一个新的 Class 方法

尝试取消实例 Mailer 方法的问题在于它固有地触发渲染和其他阻止该方法被中止的事情。但是,我仍然想将我所有的 Mailer 逻辑放在一起。

我这样做的方法是使用类方法而不是实例方法。这避免了在实例上调用方法时出现的所有钩子,ActionMailer但仍然允许我保持代码整洁和统一

class QuestionMailer
  ...
  def notify_asker_of_offtopic_flag question
    ...
  end

  def self.notify_asker_of_offtopic_flag question_if question
    if question.offtopic?
      QuestionMailer.notify_asker_of_offtopic_flag question
    end
  end
end

NB 修复使用延迟作业

除了处理delayed_job.

处理 Mailer 时,delayed_job 将始终调用.deliver返回的对象以传递邮件。当我们返回一个邮件对象时这很好,但在这种情况下我们返回 nil。delayed_job因此试图打电话.delivernil 一切都失败了。

为了解决这个问题,我们简单地返回一个包含 dupe.deliver方法的虚拟邮件对象:

class QuestionMailer
  ...
  class DummyMailer
    def deliver
      return true
    end
  end

  def notify_asker_of_offtopic_flag question
    # do mailing stuff
  end

  def self.notify_asker_of_offtopic_flag question_if question
    if question.offtopic?
      QuestionMailer.notify_asker_of_offtopic_flag question
    else
      DummyMailer.new
    end
  end
end
于 2012-07-27T11:20:12.167 回答