0

我正在尝试使用每晚运行的 rake 任务(使用 Heroku Scheduler)并在满足某些特定条件时更新一些属性。

关于应用程序的一点逻辑:

该应用程序允许用户“接受挑战”并在一年中每周阅读一本书。这很简单:用户注册,创建他们第一周要阅读的第一本书,然后可以输入他们下周要阅读的内容。在他们“排队”了下周的书后,该表单将被隐藏,直到他们的第一本书创建后 7 天。此时,排队的书被移动到列表的顶部并标记为“正在阅读”,而之前的“正在阅读”的书会下移到列表中的第二个位置。

如果用户没有“排队”一本书,系统会在最新的“当前阅读”图书创建后 7 天自动创建一个。

我需要一些建议的地方

我目前陷入困境的地方是让书籍更新属性,如果自上一本“当前阅读”书籍创建以来已经 7 天。下面是我的书本模型,该方法update_queue是在 rake 任务期间调用的方法。运行 rake 任务当前没有出现错误并正确循环代码,但它不会更改任何属性值。因此,我确定该update_queue方法中的代码在某些地方不正确,我希望您能帮助解决原因。我如何测试这一点是通过添加一本书然后手动将我的系统日期更改为提前 8 天。相当野蛮,但我没有为此应用程序编写的测试套件,这是对我来说最简单的方法:)

class Book < ActiveRecord::Base
  attr_accessible :author, :date, :order, :title, :user_id, :status, :queued, :reading
  belongs_to :user

 scope :reading_books, lambda {
    {:conditions => {:reading => 1}}
  }

  scope :latest_first, lambda {
    {:order => "created_at DESC"}
  }


  def move_from_queue_to_reading
    self.update_attributes(:queued => false, :reading => 1);
  end

  def move_from_reading_to_list
    self.update_attributes(:reading => 0);
  end

  def update_queue
    days_gone = (Date.today - Date.parse(Book.where(:reading => 1).last.created_at.to_s)).to_i

    # If been 7 days since last 'currently reading' book created
    if days_gone >= 7

        # If there's a queued book, move it to 'currently reading'
        if Book.my_books(user_id).where(:queued => true)
            new_book = Book.my_books(user_id).latest_first.where(:queued => true).last
            new_book.move_from_queue_to_reading
            Book.my_books(user_id).reading_books.move_from_reading_to_list

        # Otherwise, create a new one
        else
            Book.my_books(user_id).create(:title => "Sample book", :reading => 1)

        end
    end
  end

我的 rake 任务看起来像这样(scheduler.rake 放在 lib/tasks 中):

task :queue => :environment do
  puts "Updating feed..."
  @books = Book.all
  @books.each do |book|
    book.update_queue
  end
  puts "done."
end
4

2 回答 2

0

可能的原因是,程序流程没有进入 if days_gone >= 7 条件。

你可以通过两种方式检查

1 - 简单易行的方法(但不是很好的方法)

使用 p 语句每个都具有某种意义全文

前任:

def update_queue
    days_gone = (Date.today - Date.parse(Book.where(:reading => 1).last.created_at.to_s)).to_i

    p "days gone : #{days_gone}"   

    # If been 7 days since last 'currently reading' book created
    if days_gone >= 7
        p "inside days_gone >= 7"
    etc... 

2 - 使用 ruby​​ 调试器并使用调试点

在 Gem 文件中添加

gem 'debugger'

并在需要的地方插入断点

def update_queue
        days_gone = (Date.today - Date.parse(Book.where(:reading => 1).last.created_at.to_s)).to_i
       debugger

更多帮助

高温高压

于 2013-01-02T04:51:24.590 回答
0

我会将update_queue逻辑移至 User 模型并稍微修改 Book 模型,然后执行以下操作:

# in book.rb
# change :reading Boolean field to :reading_at Timestamp
scope :queued, where(:queued => true)
scope :earliest_first, order("books.created_at")
scope :reading_books, where("books.reading_at IS NOT NULL")

def move_from_queue_to_reading
  self.update_attributes(:queued => false, :reading_at => Time.current);
end

def move_from_reading_to_list
  self.update_attributes(:reading_at => nil);
end


# in user.rb
def update_queue
  reading_book = books.reading_books.first
  # there is an edge-case where reading_book can't be found
  # for the moment we will simply exit and not address it
  return unless reading_book 

  days_gone = Date.today - reading_book.reading_at.to_date

  # If less than 7 days since last 'currently reading' book created then exit
  return if days_gone < 7

  # wrap modifications in a transaction so they can be rolled back together
  # if an error occurs
  transaction do
    # First deal with the 'currently reading' book if there is one
    reading_book.move_from_reading_to_list

    # If there's a queued book, move it to 'currently reading'
    if books.queued.exists?
      books.queued.earliest_first.first.move_from_queue_to_reading
    # Otherwise, create a new one
    else
      books.create(:title => "Sample book", :reading_at => Time.current)
    end
  end
end

现在你可以让 Heroku 调度器每天运行一次这样的事情:

User.all.each(&:update_queue)

修改User.all为仅在需要时返回活动用户。

哦,您可以在测试时使用 timecop gem 来操作时间和日期。

于 2013-01-03T03:37:18.330 回答