2015-11-21 7 views
2

Я изучаю из rubytutorial и имею эту ошибку. Я проверил this ответ и this но все еще не работает. Я прикрепил session_helper.rb и user.rb здесь. может кто-нибудь показать мне, где я скучаю?глава 8 rubytutorial - NoMethodError: undefined метод `forget 'for nil: NilClass

1) Error: 
UsersLoginTest#test_login_with_valid_information_followed_by_logout: 
NoMethodError: undefined method `forget' for nil:NilClass 
    app/helpers/sessions_helper.rb:25:in `forget' 
    app/helpers/sessions_helper.rb:32:in `log_out' 
    app/controllers/sessions_controller.rb:19:in `destroy' 
    test/integration/users_login_test.rb:33:in `block in <class:UsersLoginTest>' 

22 runs, 50 assertions, 0 failures, 1 errors, 0 skips 

session_helper.rb

module SessionsHelper 
    # Logs in the given user. 
    def log_in(user) 
     session[:user_id] = user.id 
    end 

    def current_user 
    if (user_id = session[:user_id]) 
     @current_user ||= User.find_by(id: user_id) 
    elsif (user_id = cookies.signed[:user_id]) 
     user = User.find_by(id: user_id) 
    if user && user.authenticated?(cookies[:remember_token]) 
     log_in user 
     @current_user = user 
     end 
    end 
    end 

    def logged_in? 
     !current_user.nil? 
    end 

    # Forgets a persistent session. 
    def forget(user) 
     user.forget 
     cookies.delete(:user_id) 
     cookies.delete(:remember_token) 
    end 

    # Logs out the current user. 
    def log_out 
     forget(current_user) 
     session.delete(:user_id) 
     @current_user = nil 
    end 

    # Remembers a user in a persistent session. 
    def remember(user) 
     user.remember 
     cookies.permanent.signed[:user_id] = user.id 
     cookies.permanent[:remember_token] = user.remember_token 
    end 
    end 

user.rb

class User < ActiveRecord::Base 
    attr_accessor :remember_token 
    before_save { self.email = email.downcase } 
    validates :name, presence: true, length: { maximum: 50 } 
    VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i 
    validates :email, presence: true, length: { maximum: 255 }, 
        format: { with: VALID_EMAIL_REGEX }, 
        uniqueness: { case_sensitive: false } 
    has_secure_password 
    validates :password, presence: true, length: { minimum: 6 } 

    # Returns the hash digest of the given string. 
    def User.digest(string) 
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : 
                BCrypt::Engine.cost 
    BCrypt::Password.create(string, cost: cost) 
    end 

    # Returns a random token. 
    def User.new_token 
    SecureRandom.urlsafe_base64 
    end 

    # Remembers a user in the database for use in persistent sessions. 
    def remember 
    self.remember_token = User.new_token 
    update_attribute(:remember_digest, User.digest(remember_token)) 
    end 

    # Returns true if the given token matches the digest. 
    def authenticated?(remember_token) 
    return false if remember_digest.nil? 
    BCrypt::Password.new(remember_digest).is_password?(remember_token) 
    end 

    # Forgets a user. 
    def forget 
    update_attribute(:remember_digest, nil) 
    end 
end 

ответ

2

Ваше сообщение об ошибке указывает на то, что у вас есть:

undefined method forget' for nil:NilClass

Это означает, что вы пытались позвонить метод (forget) на объект, который не имел этого метода (nil). Глядя на часть кода, где ошибка происходит из ...

def forget(user) 
     user.forget 

... вы можете увидеть, что вы звоните забыть о переменной user. Это вызывается из метода log_out:

def log_out 
    forget(current_user) 

Итак, вы передаете current_user методу forget, а затем вызвать forget на нем. Только, это не экземпляр класса User (как вы и ожидали), который имеет метод forget, а скорее nil. nil не имеет метода забывания.

Это, вероятно, ноль, потому что вы не прошли аутентификацию и нет current_user. Одним из способов исправить это было бы проверить, если на самом деле существует текущий пользователь, прежде чем забыть его, как это:

def log_out 
    current_user && forget(current_user) 

Более сложный способ справиться с этой проблемой будет с Null Object Pattern, где current_user будет возвращать экземпляр Пользователь с минимальными разрешениями, а не nil.

+0

спасибо за ваш ответ. но я до сих пор не знаю, что делать. :) Вы имеете в виду, что база данных пуста? – Codelearner777

+0

@ Codelearner777 Нет. Я имею в виду, что нет (или аутентифицированного) пользователя. «Ниль» означает «ничего». Измените свой код, как в приведенном выше примере, и посмотрите, что произойдет. –

+0

Я пробовал, и он работает! Спасибо. Я все еще не понимаю его, и снова читаю главу 8. Я действительно предлагаю вашу помощь. – Codelearner777

1

Посмотрите на свой журнал, вы пытаетесь вызвать .forget на nil объекта:

NoMethodError: undefined method `forget' for nil:NilClass 

Это означает, что вы прошли nil в SessionsHelper#forget, поэтому ваш current_user является nil.

Вы пытаетесь выйти из системы в настоящее время не авторизованы? Если нет, должно быть что-то не так с методом current_user, потому что он возвращает nil, пока пользователь уже вошел в систему.

+1

jinx, вы получите +1 –

+0

lol, я заметил, что мы отправляем ответ в то же время, но я забыл сглазить вы :)) –

+0

спасибо за ваш ответ. но я до сих пор не знаю, что делать. :) – Codelearner777

1

Soooo, я понимаю, что это похоже на 2 года спустя ... но у меня была такая же проблема здесь, как OP ...

мое решение было (как описано в учебнике), чтобы изменить метод destroy в SessionsController от:

def destroy 
    log_out 
    redirect_to root_url 
end 

к:

def destroy 
    log_out if logged_in? 
    redirect_to root_url 
end 

В случае, если кто-то как поздно рельсы игра как я ... надеюсь, что это поможет

 Смежные вопросы

  • Нет связанных вопросов^_^