Отправка писем в выбранные пользователем даты

В моем приложении люди заходят на домашнюю страницу, вводят название ставки, которую они сделали (ради развлечения), свой адрес электронной почты, дату, на которую они хотели бы получить напоминание, и некоторые подробности о ставке. Я использую гем всякий раз, чтобы запускать это один раз в день.

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: "[email protected]"

  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 protected]", 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 protected]", 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 protected]", 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 protected]", 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">] 

После того, как терминал выполнит вышеуказанное, мой почтовый ящик будет заполнен всеми объектами Bet, у которых есть напоминание = current_date. Это доказывает, что настройки 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 exec when when» в терминале, похоже, ничего не отправляется.


person Questifer    schedule 29.07.2013    source источник
comment
Пожалуйста, поделитесь кодом, который вы используете в консоли для [запуска] метода check_bet для всех объектов ставок. Кроме того, сообщение об ошибке, которое вы получаете, действительно заканчивается на #<> или вы пропустили что-то между <>?   -  person Peter Alfvin    schedule 30.07.2013
comment
@PeterAlfvin Я добавлю это в свой пост. Нет, я просто подумал, что этот хеш не имеет значения. Спасибо   -  person Questifer    schedule 30.07.2013
comment
#<> — это нотация объекта Ruby, которая особенно актуальна в этой ситуации, поскольку она расскажет вам об объекте, который был отправлен методом check_bet.   -  person Peter Alfvin    schedule 30.07.2013
comment
@PeterAlfvin Ты прав. Добавил в свою правку. У меня были проблемы с форматированием ‹›, поэтому я исключил их, но включил тип объекта и хэш.   -  person Questifer    schedule 30.07.2013


Ответы (2)


Bet.all возвращает Array, для которого метод check_bet не определен. Чтобы вызвать check_bet для каждого экземпляра Bet, вам нужно выполнить Bet.all.each {|bet| bet.check_bet} или очиститель Bet.all.each(&:check_bet) (с поклоном @Ryan Bigg).

См. также http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects-in-batches для некоторых соображений производительности.

person Peter Alfvin    schedule 30.07.2013
comment
Вы также можете сделать Bet.all.each(&:check_bet). - person Ryan Bigg; 30.07.2013

  1. всякий раз, когда это просто драгоценный камень, который помогает вам генерировать задачи cron, он не будет запускать запланированные задачи для вас, а 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
    

Спасибо

person Mike Li    schedule 30.07.2013