在特定日期后每三天发送一次提醒电子邮件

时间:2016-04-04 22:22:50

标签: ruby-on-rails ruby-on-rails-4 rspec rspec-rails

这是我的第一篇文章,所以提前为任何新手错误道歉。我已经尝试过研究这个问题的不同解决方案,到目前为止还没有找到一个似乎适合我的特定情况。

我有个人创建evaluations的应用,如果created_at日期后7天尚未达到最低要求,我想每隔3天发送一次提醒电子邮件,提示他们动作。

reminders.rb文件如下所示,Evaluation::ASSESSMENTS_COMPLETION_WAIT_TIME设置为7.daysReminders::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

有没有更简单的方法来编写和测试它?对于我想要做的事情,这似乎过于复杂,但我找不到更简单的方法。

1 个答案:

答案 0 :(得分:0)

事实上,你似乎正在使它变得比它需要的更复杂。这里的关键是您希望使用排队后端异步发送电子邮件通知。由于提醒将在创建评估后7天发送,因此延迟电子邮件将排在#create的{​​{1}}行动中排队:

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 完成,后端将在7天后自动为您发送电子邮件。

排队后端是一个很大的主题,而不是详细说明它们的工作原理,我将在此向您指出文档:http://edgeguides.rubyonrails.org/active_job_basics.html。对于特定的排队后端,我建议使用Redis推出Sidekiq。