-->

Hartl Rails Tutorial Chapter 8.46 NoMethodError

2019-09-19 02:46发布

问题:

one my my tests receiving the following error in Chapter 8 of Hartl's Rails Tutorial.

>  1) Error:
> UsersLoginTest#test_login_with_valid_information_followed_by_logout:
> NoMethodError: undefined method `forget' for #<Class:0x000000079be3b0>
>     app/helpers/sessions_helper.rb:30:in `forget'
>     app/helpers/sessions_helper.rb:37:in `log_out'
>     app/controllers/sessions_controller.rb:18:in `destroy'
>     test/integration/users_login_test.rb:40:in `block in <class:UsersLoginTest>'

I have tried copying and pasting code exactly as it is in the tutorial, but it doesn't seem to be solving the issue.

Here is my Sessions Helper

module SessionsHelper
  def log_in(user)
    session[:user_id] = user.id
  end

  def remember(user)
    user.remember
    cookies.permanent.signed[:user_id] = user.id
    cookies.permanent[:remember_token] = user.remember_token
  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

  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 
end

And my sessions controller is below

class SessionsController < ApplicationController
  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)

    if user && user.authenticate(params[:session][:password])
      log_in user
      remember user
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

  def destroy
    log_out if logged_in?
    redirect_to root_url
    end
  end

Any suggestions would be very much appreciated!

回答1:

Here we can see the importance of really looking closely at the error message. It says there is a "No Method Error". OK. So we're doing something with the Users and there's no method. A user is a modeled thing, so let's look at app/models/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+\-.]+@[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)
    BCrypt::Password.new(remember_digest).is_password?(remember_token)
  end

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

we see that at the very end, there is a method being created called "forget"

def forget
  #something
end

That opens up the method to calls from other controllers and helpers, which you've already created in the Sessions section.