NoMethodError:nil的未定义方法`id':NilClass

时间:2017-12-06 01:33:15

标签: ruby-on-rails ruby rspec rspec-rails

我是Rspec的新手,我正在尝试做TDD。在Application Controller中,我有一个名为set current user的方法。

class ApplicationController < ActionController::Base
   protect_from_forgery with: :exception
   protected  
    def set_current_user
      @current_user ||= User.find_by_session_token(cookies[:session_token]) 
      redirect_to login_path unless @current_user
    end
  end

这是BlogsController.rb

class BlogsController < ApplicationController
  before_action :set_current_user
  before_action :has_user_and_hobby
  def blog_params
    params.require(:blog).permit(:title, :hobby_id, :user_id, :body, :rating)
  end

 ...

  def destroy
    @blog = Blog.find(params[:id])
    if @blog.user_id != @current_user.id
      flash[:notice] = "The blog #{@blog.title} only can be deleted by the author! It cannot be deleted by others."
      redirect_to hobby_blogs_path(@blog)
    else
      @blog.destroy
      flash[:notice] = "Blog '#{@blog.title}' deleted."
      redirect_back(fallback_location: root_path)
    end
  end
end

我写的测试破坏路线的rspec是:

require 'spec_helper'
require 'rails_helper'

describe BlogsController do
    let(:fuser) { FactoryGirl.create(:fuser) }
    let(:hobby) { FactoryGirl.create(:hobby)}
    let(:blog) { FactoryGirl.create(:blog, hobby_id: hobby.id, user_id: fuser.id)}
    let(:comment) { FactoryGirl.create(:comment)}

...

    describe 'delete a blog' do
      before :each do
          allow_any_instance_of(ApplicationController).to receive(:set_current_user).and_return(fuser)
          allow_any_instance_of(BlogsController).to receive(:has_user_and_hobby).and_return(blog.user_id,hobby)
          allow(User).to receive(:find).with(blog.user_id).and_return(blog.user_id)

      it 'should redirect_back' do
          delete :destroy, params:{:hobby_id =>hobby.id, :id => blog.id}
          expect(response).to be_redirect
      end
   end
end

当我尝试运行规范时,我收到错误:

Failure/Error: if @blog.user_id != @current_user.id
 NoMethodError:
   undefined method `id' for nil:NilClass

有谁知道如何帮助我?非常感谢所有的帮助。

1 个答案:

答案 0 :(得分:3)

@current_user在您的测试中为零。

你的问题就在这里。

allow_any_instance_of(ApplicationController).to receive(:set_current_user).and_return(fuser)

set_current_user实际上并不返回用户对象,它会将一个用户对象分配给@current_user变量,然后可能会重定向。

以这种方式设置用户的方式更多:

class ApplicationController < ActionController::Base
  before_action :verify_current_user!

  def current_user
    @current_user || User.find_by_session_token(cookies[:session_token])
  end

  def verify_current_user!
    redirect_to login_path unless current_user
  end
end

然后,在引用您当前登录的用户时,请调用current_user方法。该值将被记忆,因此没有性能损失。您还可以在尝试测试时存根current_user方法。在您的控制器中,始终拨打current_user而不是@current_user