在特定日期后每三天发送一次提醒电子邮件
Send reminder email every three days after certain date
这是我的第一个 post 对于任何新手错误提前道歉。我已经尝试研究针对这个问题的不同解决方案,但到目前为止还没有找到适合我的特定情况的解决方案。
我有一个个人创建 evaluations
的应用程序,如果在 created_at
日期后 7 天仍未满足最低要求,我想每 3 天发送一次提醒电子邮件以提示他们采取行动。
reminders.rb
文件如下所示,Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME
设置为 7.days
,Reminders::LIMBO_EMAIL_INTERVAL_DAYS
设置为 3
:
def self.send_peer_shortage_notifications
time = Time.current - Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME
range = time..Time.current
today = Time.current.to_date
evaluations = Evaluation.arel_table
assessments = Assessment.arel_table
left_join = evaluations
.join(assessments, Arel::Nodes::OuterJoin)
.on(evaluations[:id].eq(assessments[:evaluation_id]),
assessments[:state].in([:pending, :complete]),
assessments[:assessor_id].not_in([evaluations[:user_id],
evaluations[:manager_id]]))
.join_sources
relation = Evaluation
.in_process
.joins(left_join)
.where(created_at: range)
.group(:user_id)
.having(evaluations[:user_id].count.lt(Evaluation::MINIMUM_NUM_PEERS))
relation.find_each do |evaluation|
days_in_limbo = (today - (evaluation.created_at + Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME).to_date).to_i
if days_in_limbo % Reminders::LIMBO_EMAIL_INTERVAL_DAYS == 0
EvaluationMailer.delay.limbo_notification(evaluation)
end
end
end
我的 reminders_rspec.rb
看起来像这样(第一次测试失败,我不知道为什么):
context 'minimum number of peer assessments not in pending/complete and limbo email interval day' do
limbo_interval_array = Array.new(10) { |i| i*Reminders::LIMBO_EMAIL_INTERVAL_DAYS }
let!(:evaluation) { create(:evaluation, created_at: (Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME + limbo_interval_array.sample.days).ago) }
let!(:assessments) do
create_list(:assessment,
Evaluation::MINIMUM_NUM_PEERS,
evaluation: evaluation,
state: [:expired, :declined].sample)
end
it 'sends limbo email' do
expect { subject }.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
context 'on every non-third day since limbo' do
array = (1..20).to_a
limbo_interval_array = Array.new(10) { |i| i*Reminders::LIMBO_EMAIL_INTERVAL_DAYS }
non_limbo_interval_array = array - limbo_interval_array
let!(:evaluation) { create(:evaluation, created_at: (Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME + non_limbo_interval_array.sample.days).ago) }
let!(:assessments) do
create_list(:assessment,
Evaluation::MINIMUM_NUM_PEERS,
evaluation: evaluation,
state: [:expired, :declined].sample)
end
it 'sends nothing' do
expect { subject }.to change { ActionMailer::Base.deliveries.count }.by(0)
end
end
有没有更简单的方法来编写和测试它?这对于我正在尝试做的事情来说似乎过于复杂,但我一直无法找到更简单的方法。
确实,您似乎使事情变得比需要的更复杂。这里的关键是您想要使用队列后端来异步发送您的电子邮件通知。由于提醒将在创建评估后 7 天发送,延迟的电子邮件将排队 #create
EvaluationsController
的操作:
class EvaluationsController < ApplicationController
def create
# Do whatever it is you do to create an evaluation
if @evaluation.valid?
EvaluationMailer.delay_for(7.days).limbo_notification(evaluation.id) # Pass an ID rather than a model object, and use `find_by` within `limbo_notification`
# redirect or whatever...
end
end
现在,所有艰苦的工作都将由您的排队后端 ActiveJob
完成,它将在 7 天后自动为您发送电子邮件。
队列后端是一个很大的主题,我不会详细说明它们是如何工作的,我将向您指出此处的文档:http://edgeguides.rubyonrails.org/active_job_basics.html。对于特定的队列后端,我建议使用带有 Redis 的 Sidekiq。
这是我的第一个 post 对于任何新手错误提前道歉。我已经尝试研究针对这个问题的不同解决方案,但到目前为止还没有找到适合我的特定情况的解决方案。
我有一个个人创建 evaluations
的应用程序,如果在 created_at
日期后 7 天仍未满足最低要求,我想每 3 天发送一次提醒电子邮件以提示他们采取行动。
reminders.rb
文件如下所示,Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME
设置为 7.days
,Reminders::LIMBO_EMAIL_INTERVAL_DAYS
设置为 3
:
def self.send_peer_shortage_notifications
time = Time.current - Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME
range = time..Time.current
today = Time.current.to_date
evaluations = Evaluation.arel_table
assessments = Assessment.arel_table
left_join = evaluations
.join(assessments, Arel::Nodes::OuterJoin)
.on(evaluations[:id].eq(assessments[:evaluation_id]),
assessments[:state].in([:pending, :complete]),
assessments[:assessor_id].not_in([evaluations[:user_id],
evaluations[:manager_id]]))
.join_sources
relation = Evaluation
.in_process
.joins(left_join)
.where(created_at: range)
.group(:user_id)
.having(evaluations[:user_id].count.lt(Evaluation::MINIMUM_NUM_PEERS))
relation.find_each do |evaluation|
days_in_limbo = (today - (evaluation.created_at + Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME).to_date).to_i
if days_in_limbo % Reminders::LIMBO_EMAIL_INTERVAL_DAYS == 0
EvaluationMailer.delay.limbo_notification(evaluation)
end
end
end
我的 reminders_rspec.rb
看起来像这样(第一次测试失败,我不知道为什么):
context 'minimum number of peer assessments not in pending/complete and limbo email interval day' do
limbo_interval_array = Array.new(10) { |i| i*Reminders::LIMBO_EMAIL_INTERVAL_DAYS }
let!(:evaluation) { create(:evaluation, created_at: (Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME + limbo_interval_array.sample.days).ago) }
let!(:assessments) do
create_list(:assessment,
Evaluation::MINIMUM_NUM_PEERS,
evaluation: evaluation,
state: [:expired, :declined].sample)
end
it 'sends limbo email' do
expect { subject }.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
context 'on every non-third day since limbo' do
array = (1..20).to_a
limbo_interval_array = Array.new(10) { |i| i*Reminders::LIMBO_EMAIL_INTERVAL_DAYS }
non_limbo_interval_array = array - limbo_interval_array
let!(:evaluation) { create(:evaluation, created_at: (Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME + non_limbo_interval_array.sample.days).ago) }
let!(:assessments) do
create_list(:assessment,
Evaluation::MINIMUM_NUM_PEERS,
evaluation: evaluation,
state: [:expired, :declined].sample)
end
it 'sends nothing' do
expect { subject }.to change { ActionMailer::Base.deliveries.count }.by(0)
end
end
有没有更简单的方法来编写和测试它?这对于我正在尝试做的事情来说似乎过于复杂,但我一直无法找到更简单的方法。
确实,您似乎使事情变得比需要的更复杂。这里的关键是您想要使用队列后端来异步发送您的电子邮件通知。由于提醒将在创建评估后 7 天发送,延迟的电子邮件将排队 #create
EvaluationsController
的操作:
class EvaluationsController < ApplicationController
def create
# Do whatever it is you do to create an evaluation
if @evaluation.valid?
EvaluationMailer.delay_for(7.days).limbo_notification(evaluation.id) # Pass an ID rather than a model object, and use `find_by` within `limbo_notification`
# redirect or whatever...
end
end
现在,所有艰苦的工作都将由您的排队后端 ActiveJob
完成,它将在 7 天后自动为您发送电子邮件。
队列后端是一个很大的主题,我不会详细说明它们是如何工作的,我将向您指出此处的文档:http://edgeguides.rubyonrails.org/active_job_basics.html。对于特定的队列后端,我建议使用带有 Redis 的 Sidekiq。