Rails 4 - 如何使用 delayed_job 发送类似时事通讯的电子邮件?

Rails 4 - How to send newsletter-like emails with delayed_job?

我想每天早上向我们的用户发送新列表的摘要。使用 Ruby On Rails 4、ActiveRecord(使用 SendGrid)和延迟作业的最佳方法是什么?

我目前是这样做的:

在控制器中:

def yesterday_listings_for_users
    yesterday_listings = Listings.where('status = "0" AND (DATE(created_at) = ?)', Date.today - 1)
    if yesterday_listings.count > 0
      NotificationMailer.delay.yesterday_listings_for_users_notification
    end  
    render :nothing => true
  end

然后在邮件中:

  def yesterday_listings_for_users_notification
    @listings = Listing.where('status = "0" AND (DATE(created_at) = ?)', Date.today-1)

    mail(to: 'myemail@gmail.com', subject: "Latest Listings", from: 'no-reply@mywebsite.com')            
  end

通过使用 CRON 作业,这每天早上都会通过我的电子邮件地址向我发送报告。我的数据库中有几百个用户,我也想向他们发送这封电子邮件。

怎么做?我想知道这样的事情:

  def yesterday_listings_for_users_notification
    @listings = Listing.where('status = "0" AND (DATE(created_at) = ?)', Date.today-1)
    Users.all.each do |user|
      mail(to: user.email, subject: "Latest Listings", from: 'no-reply@mywebsite.com')          
    end
  end

但是,循环遍历数据库中的数百条记录并以延迟邮寄方法发送数百封电子邮件是否值得推荐(或适当)?

有更好的方法吗?

提前致谢!

为了简单起见,我通常更喜欢将 SidekiqSidetiq but if you want to use delayed_job I would advice you to use the whenever gem 一起使用。

Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs.

  1. gem 'whenever' 添加到您的 gem 文件
  2. 运行 命令 wheneverize . 将生成一个文件 config/schedule.rb
  3. 在您的 config/schedule.rb 中执行以下操作。

    every 1.day, :at => '11:30 am' do
      runner "User.delay.send_daily_newsletter"
    end
    
  4. 在您的 user.rb 中定义方法 send_daily_newsletter 并使用 find_each 而不是 all.each (批处理)

    def self.send_daily_newsletter
      listings = Listing.where('status = "0" AND (DATE(created_at) = ?)', Date.today - 1).select(:title).to_json
      User.select(:id, :email).find_each do |u|
        NotificationMailer.delay.send_daily_newsletter(u.email, listings)
      end
     end
    
  5. 在你的 notification_mailer.rb 中定义 send_daily_newletter

    def send_daily_newsletter(user_email, listings)
      @listings = listings
      mail(to: user_email, subject: "Latest Listings", from: 'no-reply@mywebsite.com')
    end
    

这样您将有一个延迟的工作来获取所有用户并使用单独的工作人员发送每封电子邮件,这是完成此任务的最佳方式。

Note: Do not forget to change the methods for listings in your view from, for example, listing.title to listing[:title] since we are passing the listings as json.

If you do not want to pass them as json every time to every delayed task just cache the listings in Rails.cache and clear it after you finish sending.

编辑:

如果您想使用缓存方法,因为您 运行 在 delayed_job gem 中遇到问题,请在您的邮件程序中编辑您的 send_daily_newsletter 方法。 (这就是为什么我会选择基于 redis 的 Sidekiq 而不是基于 mysql 的 delayed_job

    def send_daily_newsletter(user_email)
      @listings = Rails.cache.fetch('today_listings') { Listing.where('status = "0" AND (DATE(created_at) = ?)', Date.today - 1) }
      mail(to: user_email, subject: "Latest Listings", from: 'no-reply@mywebsite.com')
    end

在你的 user.rb

     def self.send_daily_newsletter
      User.select(:id, :email).find_each do |u|
        NotificationMailer.delay.send_daily_newsletter(u.email)
      end
      Rails.cache.clear('today_listings')
     end

祝你好运。我做这些电子邮件通讯已经有一段时间了,它们真的很痛苦:D