Rails5如何每月发送电子邮件报告?

时间:2019-06-18 21:46:36

标签: ruby-on-rails whenever rails-activejob

我正在尝试设计一个报告系统,以通知管理员有关客户服务应用程序的用户消息传递速率和响应时间。

我有一个看起来像这样的租户类:

class Tenant < ApplicationRecord

  has_many :users
  has_many :chat_messages

end

还有一个如下所示的用户类:

class User < ApplicationRecord

  belongs_to :organization
  has_many :authored_conversations, class_name: 'Conversation', :as => :author
  has_many :chat_messages, as: :user, dependent: :nullify
  has_many :received_conversations, :as => :receiver, class_name: 'Conversation'

  def conversations
    authored_conversations + received_conversations
  end

  def response_time
    # calculate the user's average response time
  end

end

现在,我们必须手动运行rake任务来处理业务。 但是,使流程自动化会更好。

因此设计了这样的ReportGenerator类:

class ReportGenerator

  def initialize(org_id)
    @organization = Organization.find org_id
  end

  def generate_report
    report = Report.generate(@organization)
    ReportMailer.new_report(report).deliver_later
  end

end

我也将邮件设置为:

class ReportMailer < ApplicationMailer
  default from: ENV["DEFAULT_MAILER_FROM"],
          template_path: 'mailers/chat_message_mailer'

  def new_message(report, recipient)
    @report = report
    @recipient = recipient
    @subject = "Monthly report for #{report.created_at}"
    @greeting = "Hi, #{recipient.name}"
    @body = @report.body
    mail(to: @recipient.email, subject: @subject)
  end

end

但是,我正在努力制定时间表,我发现this example 但是我相信这样做可以很快地摆脱困境。我也想知道,什么是最好的方法?是执行后台作业还是耙任务?

1 个答案:

答案 0 :(得分:3)

我认为您需要解决两件事:一种在常规基础上运行所需代码的方法,并且需要找到放置代码的位置。

CRON长期以来一直是定期启动和运行任务的默认选项。 whenever gem是一种众所周知的简单解决方案,用于在通用环境中部署应用程序时管理CRON。除非您所处的环境不支持CRON或偏爱其他解决方案(例如,Heroku偏爱Scheduler),否则我会在任何时候都选择使用CRON。

关于将代码放置在哪里,我认为不需要像sidekiq这样的后台处理工具,因为通过CRON运行代码已经在后台进行了某种处理。此外,我认为在rake任务中实现此目标没有任何好处。瑞克任务很难测试,您仍然需要运行应用程序代码来查询数据库并发送电子邮件。

我只会使用rails runner来调用创建和发送所有电子邮件的单个方法。也许像这样

rails runner "ReportGenerator.create_for_all_organisations"

您的ReportGenerator的更改如下:

class ReportGenerator
  def self.create_for_all_organisations
    Organization.find_each { |organization| new(organization).generate_report }
  end

  def initialize(organization)
    @organization = organization
  end

  def generate_report
    report = Report.generate(@organization)
    ReportMailer.new_report(report).deliver_later
  end
end

这避免了依赖其他sidekiq之类的宝石,并允许在您的应用程序中包含代码(而不是作为外部rake任务)。在您的应用程序中包含代码使测试和维护代码更加容易。