Rails - 使用 rake 任务更新属性.需要帮助疑难解答模型方法代码 [英] Rails - Update attributes using rake task. Need help troubleshooting model method code
问题描述
我正在尝试使用每晚运行的 rake 任务(使用 Heroku 调度程序)并在满足某些特定条件时更新一些属性.
I am trying to use a rake task that will run every night (using Heroku Scheduler) and update some attributes if some certain criteria is met.
关于应用程序的一点逻辑:
该应用程序允许用户接受挑战"并在一年中每周阅读一本书.这非常简单:用户注册,创建他们第一周将阅读的第一本书,然后可以输入他们下周要阅读的内容.在他们排队"下周的书后,该表格将被隐藏,直到他们的第一本书创建后 7 天.此时,排队的图书将移至列表顶部并标记为当前正在阅读",而之前当前正在阅读"的图书将移至列表中的第二个位置.
The application allows users to "take the challenge" and read a book a week over the course of a year. It's pretty simple: users sign up, create the first book that they will read for their first week, then can enter what they're going to read next week. After they've "queued" up next week's book, that form is then hidden until it's been 7 days since their first book was created. At that point, the book that was queued up gets moved to the top of the list and marked as 'currently reading', while the previous 'currently reading' book moves down to the second position in the list.
如果用户没有排队"一本书,如果距离最新的当前正在阅读"的书已经过去 7 天,系统会自动创建一本书.
And IF a user doesn't 'queue' a book, the system will automatically create one if it's been 7 days since the latest 'currently reading' book was created.
我需要什么建议
如果距离上一本当前正在阅读"的图书创建已经过去 7 天,我目前遇到的问题是让图书更新属性.下面是我的书籍模型,方法 update_queue
是在 rake 任务期间调用的.运行 rake 任务当前不会出现错误并正确循环代码,但它只是不会更改任何属性值.因此,我确定 update_queue
方法中的代码在某些地方不正确,我希望您能帮助解决原因.我测试的方法是添加一本书,然后手动将系统日期更改为提前 8 天.相当野蛮,但我没有为此应用程序编写的测试套件&这是对我来说最简单的方法:)
The place I'm currently stuck is getting the books to update attributes if it's been 7 days since the last 'currently reading' book was created. Below is my book model and the method update_queue
is what gets called during the rake task. Running the rake task currently gives no errors and properly loops through the code, but it just doesn't change any attribute values. So I'm sure the code in the update_queue
method is not correct somewhere along the lines and I would love your help troubleshooting the reason why. And how I'm testing this is by adding a book then manually changing my system's date to 8 days ahead. Pretty barbaric, but I don't have a test suite written for this application & it's the easiest way to do it for me :)
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
推荐答案
我会将 update_queue
逻辑移到 User 模型并稍微修改 Book 模型,然后执行以下操作:
I would move the update_queue
logic to the User model and modify the Book model somewhat, and do something like this:
# 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 调度程序每天运行一次:
Now you can have the Heroku scheduler run something like this once a day:
User.all.each(&:update_queue)
修改 User.all
以仅在需要时返回活动用户.
Modify User.all
to only return active users if you need to.
哦,您可以在测试时使用 timecop gem 来操作时间和日期.
Oh, and you can use the timecop gem to manipulate times and dates when testing.
这篇关于Rails - 使用 rake 任务更新属性.需要帮助疑难解答模型方法代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!