NoMethodError:undefined method `id' for nil:NilClass
NoMethodError:undefined method `id' for nil:NilClass
我是 Rspec 的新手,我正在尝试进行 TDD。在应用程序控制器中,我有一个名为 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
有人知道如何帮助我吗?非常感谢所有帮助。
@current_user
在您的测试中为零。
你的问题就在这里。
allow_any_instance_of(ApplicationController).to receive(:set_current_user).and_return(fuser)
set_current_user
实际上 return 不是一个用户对象,它将一个分配给 @current_user
变量,然后可能会重定向。
更重要的是 rails 以这种方式设置您的用户:
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
.
我是 Rspec 的新手,我正在尝试进行 TDD。在应用程序控制器中,我有一个名为 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
有人知道如何帮助我吗?非常感谢所有帮助。
@current_user
在您的测试中为零。
你的问题就在这里。
allow_any_instance_of(ApplicationController).to receive(:set_current_user).and_return(fuser)
set_current_user
实际上 return 不是一个用户对象,它将一个分配给 @current_user
变量,然后可能会重定向。
更重要的是 rails 以这种方式设置您的用户:
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
.