Rails 4.1测试返回未定义的方法`authenticate'为零:NilClass

时间:2014-09-09 07:00:12

标签: ruby-on-rails authentication rspec

我正在使用Ruby 2.1.2和Rails 4.1.5完成树屋教程,我在auth教程中遇到了我的测试问题。

教程说这段代码应该通过:

def create
    user = User.find(params[:email])
    if user && user.authenticate(params[:password])
        session[:user_id] = user.id
        redirect_to todo_lists_path
    else
        flash.now[:error] = "There was an error logging in. Please check your email and password"
        render action: 'new'
    end
end

以下是我的测试:

describe "POST 'create'" do

        context "with correct credentials" do
            let!(:user){
                User.create(
                first_name: "Jason", 
                last_name: "Seifer", 
                email: "jason@teamtreehouse.com", 
                password: "teamtreehouse1234",
                password_confirmation:"teamtreehouse1234")}

          it "redirects to the todo list path" do
            post :create, email: "jason@teamtreehouse.com", password: "treehouse1234"
            expect(response).to be_redirect
            expect(response).to redirect_to(todo_lists_path)
          end

          it "finds the user" do
            expect(User).to receive(:find_by).with({email: "jason@teamtreehouse.com"}).and_return(user)
            post :create, email: "jason@teamtreehouse.com", password: "treehouse1234"
          end

          it "authenticates the user" do
            User.stub(:find_by).and_return(user)
            expect(user).to receive(:authenticate)
            post :create, email: "jason@teamtreehouse.com", password: "treehouse1234"
         end

          it "sets the user id in the session" do
            post :create, email: "jason@teamtreehouse.com", password: "treehouse1234"
            expect(session[:user_id]).to eq(user.id)
          end

          it "sets the flash success messagge" do
            post :create, email: "jason@teamtreehouse.com", password: "treehouse1234"
            expect(flash[:success]).to eq("Thanks for logging in!")
          end
        end

        context "with blank credentials" do
          it "renders the new template" do
            post :create
            expect(response).to render_template('new')
          end
          it "sets the flash error messagge" do
            post :create, email: "jason@teamtreehouse.com", password: "treehouse1234"
            expect(flash[:error]).to eq("There was an error logging in. Please check your email and password")
          end
        end

        context "with incorrect credentials" do
          let!(:user){
            User.create(
            first_name: "Jason", 
            last_name: "Seifer", 
            email: "jason@teamtreehouse.com", 
            password: "teamtreehouse1234",
            password_confirmation:"teamtreehouse1234")}

          it "renders the new template" do
            post :create, email: user.email, password: "fuckingpassword"
            expect(response).to render_template('new')
          end
          it "sets the flash error messagge" do
            post :create, email: user.email, password: "fuckingpassword"
            expect(flash[:error]).to eq("There was an error logging in. Please check your email and password")
          end
       end
end

这给了我错误undefined method `authenticate' for nil:NilClass我通过测试的唯一方法是:

class UserSessionsController < ApplicationController
    def new
    end

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

        if user.nil?
            flash[:error] = "There was an error logging in. Please check your email and password"
            render action: 'new'
        else
            user.authenticate(params[:password])
            session[:user_id] = user.id
            flash[:success] = "Thanks for logging in!"
            redirect_to todo_lists_path
        end 
    end
end

我知道它很丑陋但它确实有效,我需要测试它是否拒绝使用正确的用户进行身份验证但密码错误。测试返回了两个错误:

1) UserSessionsController POST 'create' with incorrect credentials renders the new template
Failure/Error: expect(response).to render_template('new')
   expecting <"new"> but rendering with <[]>

2) UserSessionsController POST 'create' with incorrect credentials sets the flash error messagge
Failure/Error: expect(flash[:error]).to eq("There was an error logging in. Please check your email and password")
expected: "There was an error logging in. Please check your email and password"
        got: nil

第一个例子失败了,因为无论什么原因(可能是rspec)if子句都不处理user.authenticate(params [:password])因为它返回一个哈希值。

请注意,以下代码适用于bin / rails控制台:

> user = User.create(first_name:"John", last_name: "Doe", email: "jon.doe@me.com", password: "password", password_confirmation: "password")
> user.save
> if user && user.authenticate("password")
> puts "wawa"
> end
wawa
=> nil

我尝试过重构create方法,以便在分配时进行身份验证无效:

  def create
    user = User.find_by(email: params[:email]).authenticate(params[:password])

    if user.nil? || user == false
        flash[:error] = "There was an error logging in. Please check your email and password"
        render action: 'new'
    else
        session[:user_id] = user.id
        flash[:success] = "Thanks for logging in!"
        redirect_to todo_lists_path
    end 
  end

我再次获得undefined method `authenticate' for nil:NilClass

2 个答案:

答案 0 :(得分:1)

发现它不在测试中的逻辑中的错误,我使用不正确的凭据treehouse123测试密码,而不是在我的用户teamtreehouse123中创建的密码。

灵感来自于这个调试代码:

    def create
      user = User.find_by(email: params[:email])
      if (user.nil? == false) 
        if user.authenticate(params[:password]) 
          puts user.authenticate(params[:password])
          puts "NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN Batman!"
          session[:user_id] = user.id
          flash[:success] = "Thanks for logging in!"
          redirect_to todo_lists_path
        else 
          puts user.authenticate(params[:password])
          puts "waka waka waka waka waka waka waka waka waka waka waka waka waka waka waka waka"
          flash[:error] = "There was an error logging in. Please check your email and password"
          render action: "new"
        end
      else
        flash[:error] = "There was an error logging in. Please check your email and password"
        render action: "new"
      end
    end

user.authenticate(params[:password])总是返回false,无论我做了什么。

树屋代码是正确的,但我将所有teamtreehouse123更改为password

答案 1 :(得分:0)

undefined method 'authenticate' for nil:NilClass是一个经典的Rails错误。

authenticate方法中的错误从不。它总是在它之前的部分。

此处,User.find_by(email: params[:email])出错。在这种情况下,这部分代码返回nil。所以Rails正试图执行nil.authenticate(params[:password])

请检查您的params[:email]值或用户列表。