I would like this before filter to run every time the page is loaded (for now) to check if an item is over 7 days old or not and if so, run some actions on it to update its attributes.
I have before_filter :update_it
in the application controller. update_it
is defined below that in the same controller as:
def update_it
@books = Book.all
@books.each do |book|
book.update_queue
end
end
Then update_queue
is defined in the book model. Here's everything in the model that pertains to this:
scope :my_books, lambda {|user_id|
{:conditions => {:user_id => user_id}}
}
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
currently_reading = Book.my_books(user_id).reading_books.last
currently_reading.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
My relationship is that a book belongs_to a user and a user has_many books. I'm showing these books in the view through the user show view, not that it matters though.
So the errors I keep getting are that move_from_queue_to_reading
and move_from_reading_to_list
are undefined methods. How can this be? I'm clearly defining them and then calling them below. I really am at a loss and would greatly appreciate some insight into what I'm doing wrong. I'm a beginner here, so any structured criticism would be great :)
EDIT
The exact error message I get and stack trace is as follows:
NoMethodError in UsersController#show
undefined method `move_from_queue_to_reading' for nil:NilClass
app/models/book.rb:41:in `update_queue'
app/controllers/application_controller.rb:22:in `block in update_it'
app/controllers/application_controller.rb:21:in `each'
app/controllers/application_controller.rb:21:in `update_it'
I suspect that the collection returned is an empty array (which is still 'truthy' when tested). So calling .last
is returning nil
to the new_book
and currently_reading
local variables. Try changing:
if Book.my_books(user_id).where(:queued => true)
to:
if Book.my_books(user_id).where(:queued => true).exists?
Additionally, you are modifying the scope when finding currently_reading
. This can potentially cause the query to again return no results. Change:
currently_reading.move_from_reading_to_list
to:
currently_reading.move_from_reading_to_list if currently_reading