Rails – 使用rake任务更新属性。 需要帮助排除模型方法代码

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

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

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

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

我需要一些建议

我目前所困的地方是,如果自上次“当前阅读”书籍创建以来已经过了7天,那么书籍就会更新属性。 下面是我的书模型,方法update_queue是在rake任务期间调用的内容。 运行rake任务当前没有错误并正确循环代码,但它不会更改任何属性值。 所以我确定update_queue方法中的代码在某些地方不正确,我很乐意帮助您解决原因。 我如何测试这个是通过添加一本书然后手动将我的系统日期更改为提前8天。 非常野蛮,但我没有为这个应用程序编写的测试套件,这是最简单的方法为我做:)

 class Book  {: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 

我会将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来测试时间和日期。

可能原因是,程序流程不在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 

更多帮助

HTH