Rails — Использование before_filter для запуска метода

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

У меня есть before_filter :update_it в контроллере приложений. update_it определяется ниже, чем в том же контроллере, что и:

def update_it
  @books = Book.all
  @books.each do |book|
    book.update_queue
  end
end

Затем в модели книги определяется update_queue. Вот все в модели, что относится к этому:

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

Мои отношения таковы, что книга принадлежит пользователю, а у пользователя есть_много книг. Я показываю эти книги в представлении через пользовательское представление, хотя это не имеет значения.

Итак, ошибки, которые я продолжаю получать, заключаются в том, что move_from_queue_to_reading и move_from_reading_to_list являются неопределенными методами. Как это может быть? Я четко определяю их, а затем называю их ниже. Я действительно в недоумении и был бы очень признателен за понимание того, что я делаю неправильно. Я здесь новичок, поэтому любая структурированная критика будет отличной :)

ИЗМЕНИТЬ

Точное сообщение об ошибке, которое я получаю, и трассировка стека выглядят следующим образом:

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'

person Trevan Hetzel    schedule 02.01.2013    source источник
comment
Можете ли вы проверить, что переменные new_book и currently_reading не являются nil?   -  person PinnyM    schedule 03.01.2013
comment
Эти два метода нельзя найти в разделе protected или private?   -  person Don Cruickshank    schedule 03.01.2013
comment
@PinnyM new_book не равен нулю, если я запускаю new_book = Book.where(:queued => true).last в консоли. Возвращает книгу. То же самое с currently_reading.   -  person Trevan Hetzel    schedule 03.01.2013
comment
@DonCruickshank Нет, это не так.   -  person Trevan Hetzel    schedule 03.01.2013
comment
Возможно, но это не то же самое, что Book.my_books(user_id).where(:queued => true).last. В любом случае может помочь, если вы опубликуете трассировку стека.   -  person PinnyM    schedule 03.01.2013
comment
Просто написал выше в вопросе. Я не знаю, как это сделать в консоли, так как my_books — это область действия.   -  person Trevan Hetzel    schedule 03.01.2013
comment
В соответствии с вашей трассировкой стека метод-нарушитель вызывается для нулевого объекта: undefined method move_from_queue_to_reading' for nil:NilClass`   -  person PinnyM    schedule 03.01.2013
comment
Ах хорошо. Так что .my_books(user_id) как-то недействительно. Это найдено выше в scope :my_books. Эми, я неправильно называю этот метод области видимости?   -  person Trevan Hetzel    schedule 03.01.2013
comment
Подожди, знаешь что. Я нигде не определяю user_id в этой модели. Может ли это быть проблема?   -  person Trevan Hetzel    schedule 03.01.2013
comment
Нет, это не так. user_id является атрибутом текущего объекта book - см. обновление моего ответа.   -  person PinnyM    schedule 03.01.2013


Ответы (1)


Я подозреваю, что возвращаемая коллекция представляет собой пустой массив (который все еще «правдив» при проверке). Таким образом, вызов .last возвращает nil в локальные переменные new_book и currently_reading. Попробуйте изменить:

if Book.my_books(user_id).where(:queued => true)

to:

if Book.my_books(user_id).where(:queued => true).exists?

Кроме того, вы изменяете область при поиске currently_reading. Это потенциально может привести к тому, что запрос снова не даст результатов. Сдача:

currently_reading.move_from_reading_to_list

to:

currently_reading.move_from_reading_to_list if currently_reading
person PinnyM    schedule 02.01.2013
comment
Спасибо за ответ. Тем не менее, все еще получаю неопределенные методы. - person Trevan Hetzel; 03.01.2013
comment
Я думаю, вы только что решили проблему, из-за которой я рвал на себе волосы в течение 3 дней. Я еще немного попробую, но клянусь, если ты только что решил мою проблему, я приду туда, где ты есть, и обниму тебя. - person Trevan Hetzel; 03.01.2013
comment
Пожалуйста. Не. Рад помочь. - person PinnyM; 03.01.2013
comment
:) Итак, я определенно добился прогресса, потому что каждый раз, когда страница загружается, она просматривает все 300 книг в базе данных и проверяет их обновление, и это занимает около 45 секунд, поэтому мне придется это изменить (я думаю он обновляет ВСЕ книги в БД, а не только те, которые мы хотим). Так что, как только это произойдет, книга не будет добавлена, если в очереди нет ни одной. Вам подходит Book.my_books(user_id).create(:title => "Sample book", :reading => 1)? - person Trevan Hetzel; 03.01.2013
comment
Неа. Попробуй, user.books.create(:title => "Sample book", :reading => 1). Это предполагает, что ваша книга belongs_to принадлежит пользователю, который has_many книги. - person PinnyM; 03.01.2013
comment
Хорошо, сейчас обновляются все записи с этим изменением. Я думаю, что каким-то образом удваиваю количество книг каждый раз, когда обновляю страницу, потому что загрузка всех этих книг занимает буквально 2 минуты. Я даже не могу сказать, что он делает, он движется так быстро. Мой компьютер звучит так, будто он вот-вот взорвется - person Trevan Hetzel; 03.01.2013
comment
Возможно, эта логика не совсем то, что вы хотели. Не могли бы вы пересмотреть свой вопрос и уточнить, что именно вы хотите сделать с этим before_filter? А еще лучше, сделайте это отдельным вопросом, так как это не связано с проблемой, с которой вы начали. - person PinnyM; 03.01.2013
comment
Ну, я писал об этом раньше, и логика может быть объяснена лучше там. Тогда логика была немного другой, так как я собирался запустить задание cron вместо фильтра перед. stackoverflow.com/questions/14116242/ - person Trevan Hetzel; 03.01.2013