我如何才能自动为尚未确认的用户重新发送一封 Devise 确认电子邮件,但只发送一次?

How can I resend a Devise confirmation email automatically, but only once, for users who have not confirmed?

我正在使用 Rails 和 Devise confirmable。当用户注册时,Devise 会自动向他们发送一封确认电子邮件。如果他们在三天后仍未确认,我想向他们发送另一封带有新令牌的确认电子邮件。如果他们在第二封电子邮件后仍未确认,我们应该不再发送给他们。在时间轴上绘制:

我不想在我的用户模型中添加一个新列来跟踪向他们发送确认电子邮件的次数,因为我认为我可以在每天运行的 Worker 中使用这些信息来做到这一点我们已经有了。但是,我在正确理解逻辑方面遇到了一些困难。

这是我目前的情况:

# workers/resend_confirmation_worker.rb

class ResendConfirmationWorker
  include Sidekiq::Worker
  sidekiq_options queue: :resend_confirmation, retry: false

  def perform
    users = User.where('confirmation_sent_at IS NOT NULL and
                        confirmed_at IS NULL')
    users.each do |user|
      return if user.created_at < Time.zone.now - 4.days || user.created_at > Time.zone.now - 3.days
      user.resend_confirmation!
  end
end

# config/clock.rb

module Clockwork
  every(1.day, 'Resend confirmation') { ResendConfirmationWorker.perform_async }
end

感谢任何帮助或改进建议。

如果您要每天 运行 工作人员一次,您可能会使用类似的东西:

User.where('
  confirmed_at IS NULL
  AND created_at >= ?
  AND created_at <= ?
', 2.days.ago.beginning_of_day, 2.days.ago.end_of_day)

如果您在星期三 运行 这样做,它会获取星期一注册的所有未确认用户。

d = 2.days.ago
users = User.where.not(confirmation_sent_at: nil)
            .where(confirmed_at: nil)
            .where(created_at: d.beginning_of_day..d.end_of_day)

users.find_each do |user|
  user.resend_confirmation!
end

发布的答案几乎是完美的,但是您需要使用 user.send_confirmation_instructions 而不是 resend_confirmation!,并且如果工人 运行 一天不止一次由于意外(例如由于 dyno 重启),人们可能会收到太多确认电子邮件。

现在我想弄清楚的是 why my tests aren't working