【问题标题】:Sending emails on user-selected dates在用户选择的日期发送电子邮件
【发布时间】:2013-07-29 21:53:19
【问题描述】:

我的应用程序涉及到人们来到主页,输入他们下注的名称(为了好玩)、他们的电子邮件地址、他们希望收到提醒的日期,以及有关下注的一些详细信息。我正在使用when gem 每天运行一次。

bet.rb

class Bet < ActiveRecord::Base
  attr_accessible :details, :email, :name, :reminder, :sent

  # Sends user a reminder if current_date is equal to the reminder date of the bet
  def check_bet
    current_date = Time.now.strftime("%Y-%m-%d").to_s
    @bets = Bet.all
    @bets.each do |bet|
    BetMailer.bet_reminder(bet).deliver and bet.sent = true and bet.save! if bet.reminder.to_s == current_date
    end 
  end
end

schedule.rb

every :day, :at => '5:00pm' do
  runner "Bet.check_bet"
end 

bet_mailer.rb

class BetMailer < ActionMailer::Base
  default from: "from@example.com"

  def bet_reminder(bet)
    @bet = bet

    mail to: bet.email, subject: bet.name + " Reminder"
  end
end

当 current_date 等于他们想要提醒的日期(提醒)时,我已成功发送电子邮件。为了测试这一点,我进入了 rails 控制台,选择了一个特定的 Bet 对象,并在其上运行了 check_bet 方法:

1.9.2p320 :013 > Bet.last.check_bet
  Bet Load (2.8ms)  SELECT "bets".* FROM "bets" ORDER BY "bets"."id" DESC LIMIT 1
  Bet Load (0.9ms)  SELECT "bets".* FROM "bets" 
   (0.2ms)  BEGIN
   (0.3ms)  COMMIT
   (0.2ms)  BEGIN
   (0.3ms)  COMMIT
   (0.2ms)  BEGIN
   (0.2ms)  COMMIT
 => [#<Bet id: 3, name: "Newsroom", email: "email@email.com", reminder: "2013-07-30", details: "Mac and Will are going to get back together.", sent: false, created_at: "2013-07-29 17:23:13", updated_at: "2013-07-29 17:23:13">, #<Bet id: 4, name: "Testing", email: "email@email.com", reminder: "2013-07-29", details: "This is a test", sent: true, created_at: "2013-07-29 18:38:42", updated_at: "2013-07-29 20:17:34">, #<Bet id: 5, name: "Cheaper iPhone", email: "email@email.com", reminder: "2013-07-29", details: "I bet Dad that there will be a cheaper iphone in th...", sent: true, created_at: "2013-07-29 20:39:33", updated_at: "2013-07-29 20:50:14">, #<Bet id: 6, name: "My grades", email: "email@email.com", reminder: "2013-07-29", details: "My grades this year will be > 84% average", sent: true, created_at: "2013-07-29 20:56:18", updated_at: "2013-07-29 21:14:21">] 

在终端完成上述操作后,我的邮箱中充满了所有提醒 = current_date 的 Bet 对象。这证明 SMTP 设置正常,并且我认为的代码工作正常。

但是,当我尝试对所有投注对象运行 check_bet 方法时,我收到一个未定义的方法错误:

1.9.2p320 :016 > Bet.all.check_bet
  Bet Load (1.8ms)  SELECT "bets".* FROM "bets" 
NoMethodError: undefined method `check_bet' for #<Array:0x007ffdd2c8c6c0>
    from (irb):16
    from /Users/bvlaar/.rvm/gems/ruby-1.9.2-p320@rails3tutorial/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
    from /Users/bvlaar/.rvm/gems/ruby-1.9.2-p320@rails3tutorial/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
    from /Users/bvlaar/.rvm/gems/ruby-1.9.2-p320@rails3tutorial/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>

'

此外,当我在终端中运行“bundle execwhen”命令时,似乎没有发送任何内容。

【问题讨论】:

  • 请分享您在控制台中使用的代码,以“在所有投注对象上[运行] check_bet 方法”。另外,您收到的错误消息是否真的以#&lt;&gt; 结尾,还是您在&lt;&gt; 之间遗漏了什么?
  • @PeterAlfvin 我会将其添加到我的帖子中。不,我只是认为哈希无关紧要。谢谢
  • #&lt;&gt; 是 Ruby 的对象表示法,在这种情况下尤其重要,因为它会告诉您发送 check_bet 方法的对象。
  • @PeterAlfvin 你是对的。在我的编辑中添加它。 “”有格式问题,所以我排除了它们,但包括了对象类型和哈希。

标签: ruby-on-rails ruby actionmailer whenever


【解决方案1】:

Bet.all 返回一个Array,未定义check_bet 方法。要在Bet 的每个实例上调用check_bet,您需要执行Bet.all.each {|bet| bet.check_bet} 或清洁器Bet.all.each(&amp;:check_bet)(向@Ryan Bigg 点头)。

另请参阅http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects-in-batches,了解一些性能注意事项。

【讨论】:

  • 你也可以Bet.all.each(&amp;:check_bet)
【解决方案2】:
  1. whenever 只是一个帮助您生成 cron 任务的 gem,它不会为您运行任何计划任务,crontab 会。

  2. 我认为像这样每小时运行调度程序会更好

    every :hour do
      runner "Bet.check_bet"
    end 
    
  3. 然后,在您的 Bet 模型类中,您可以这样做:

    class Bet < ActiveRecord::Base
      attr_accessible :details, :email, :name, :reminder, :sent
    
      # Sends user a reminder if current_date is equal to the reminder date of the bet
      def self.check_bet
        current_date = Time.now.strftime("%Y-%m-%d").to_s
        self.where(:reminder => current_date).each do |bet|
          BetMailer.bet_reminder(bet).deliver # later you can use some background job gem like sidekiq, rescue or delayed_job to send email, otherwise the performance might be a issue
          bet.update_attribute(:sent, true)
        end
       end 
     end
    end
    

谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-11
    • 1970-01-01
    • 2016-11-23
    • 1970-01-01
    • 2022-08-10
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    相关资源
    最近更新 更多