我真的在与Rspec DSL挣扎!我在SO和互联网上阅读了很多内容,所以我发布了我的特定问题,因为我的软弱无法解决问题。
在我的控制器中有一个更新用户电子邮件的帖子方法。工作正常,但我正在努力与规范,因为我得到的是NilClass的未定义方法(即使我已经尝试了对每个对象和方法等进行存根)。
users_controller.rb
def update_user_email
@user = User.find_by_id(params[:id])
new_email = params[:user][:new_email].downcase.strip
user_check = User.find_by_email('new_email')
if user_check.blank?
@user.email = new_email
@user.save
flash[:notice] = "Email updated to #{new_email}"
else
flash[:alert] = "This email is already being used by someone else!"
end
respond_with @user do |format|
format.html { redirect_to admin_user_path(@user) }
format.json { head :no_content }
end
end
这是我想写的规范。我应该写什么测试,如果不是这样,我该怎么做才能防止NilClass错误的未定义方法!
users_controller_spec.rb
describe Admin::UsersController do
let!(:user) { FactoryGirl.create(:user, password: 'oldpass', email: 'bar@foo.com') }
...
describe "admin actions for each user" do
it "resets user email" do
post :update_user_email, {user: {new_email: 'foo@bar.com'} }
response.status.should == 200
end
end
...
end
错误:
Admin::UsersController admin actions for each user resets user email
Failure/Error: post :update_user_email, {user: {new_email: 'foo@bar.com'} }
NoMethodError:
undefined method `email=' for nil:NilClass
答案 0 :(得分:1)
问题是您还需要传递您想要更新的User
的ID。失败的行是@user.email = new_email
,因为@user
是零。
要让您的测试立即通过,您需要将post
方法更改为:
post :update_user_email, {id:'bar@foo.com', user: {new_email: 'foo@bar.com'} }
顺便说一下,可以说你可能更好地在UsersController#update
方法中执行此操作,以便维护RESTful路由。至于执行唯一的电子邮件地址 - 在User
类中进行验证可能会更好。
答案 1 :(得分:1)
失败的行是:
@user = User.find_by_id(params[:id)
由于您在测试期间没有传入id,因此找不到用户,因此您尝试调用email = on nil。以下是清理控制器和测试的方法。
class YourController < ApplicationController
before_filter :find_user, only: [:update_user_email]
def update_user_email
new_email = params[:user][:new_email].downcase.strip
user_check = User.where(email: new_email)
if user_check.blank?
@user.email = new_email
@user.save
flash[:notice] = "Email updated to #{new_email}"
else
flash[:alert] = "This email is already being used by someone else!"
end
respond_with @user do |format|
format.html { redirect_to admin_user_path(@user) }
format.json { head :no_content }
end
end
def find_user
@user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:error] = "It looks like that user does not exist"
# redirect or render
end
end
# your test
describe "admin actions for each user" do
it "resets user email" do
post :update_user_email, id: user.id, user: {new_email: 'foo@bar.com'}
response.status.should == 200
end
end
您可能还需要考虑将逻辑移出控制器并转移到服务对象中。控制器方法有点长。
答案 2 :(得分:0)
在post :update_user_email
中你没有传递:id ...所以@user = User.find_by_id...
找不到用户,所以@user是一个零对象。
post :update_user_email, id: user.id, {user: {new_email: 'foo@bar.com'} }