我正在研究Rails教程并按照说明操作,我总是得到预期的结果,但在完成chapter 10之后,我得到了以下错误,我找不到问题所在。< / p>
1) UsersController PUT 'update' authentication of edit/update pages for non-signed-in users should deny access to 'edit'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
2) UsersController PUT 'update' authentication of edit/update pages for non-signed-in users should deny access to 'update'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
3) UsersController PUT 'update' authentication of edit/update pages for signed-in users should require matching users for 'edit'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
4) UsersController PUT 'update' authentication of edit/update pages for signed-in users should require matching users for 'update'
Failure/Error: @user = Factory(:user)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./spec/controllers/users_controller_spec.rb:259:in `block (4 levels) in <top (required)>'
5) UsersController DELETE 'destroy' as a non-signed-in user should deny access
Failure/Error: delete :destroy, :id => @user
NoMethodError:
undefined method `admin?' for nil:NilClass
# ./app/controllers/users_controller.rb:68:in `admin_user'
# ./spec/controllers/users_controller_spec.rb:303:in `block (4 levels) in <top (required)>'
应用程序运行良好,功能已完成,但测试未通过。最初我以为可能有拼写错误,然后我仔细检查,看看我是否错过了什么,但没有运气......
作为参考,这是我的RSpec测试:
describe "PUT 'update'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
describe "failure" do
before(:each) do
@attr = { :email => "", :name => "", :password => "",
:password_confirmation => "" }
end
it "should render the 'edit' page" do
put :update, :id => @user, :user => @attr
response.should render_template('edit')
end
it "should have the right title" do
put :update, :id => @user, :user => @attr
response.should have_selector("title", :content => "Edit user")
end
end
describe "success" do
before(:each) do
@attr = { :name => "New Name", :email => "user@example.org",
:password => "barbaz", :password_confirmation => "barbaz" }
end
it "should change the user's attributes" do
put :update, :id => @user, :user => @attr
@user.reload
@user.name.should == @attr[:name]
@user.email.should == @attr[:email]
end
it "should redirect to the user show page" do
put :update, :id => @user, :user => @attr
response.should redirect_to(user_path(@user))
end
it "should have a flash message" do
put :update, :id => @user, :user => @attr
flash[:success].should =~ /updated/
end
end
describe "authentication of edit/update pages" do
before(:each) do
@user = Factory(:user)
end
describe "for non-signed-in users" do
it "should deny access to 'edit'" do
get :edit, :id => @user
response.should redirect_to(signin_path)
end
it "should deny access to 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(signin_path)
end
end
describe "for signed-in users" do
before(:each) do
wrong_user = Factory(:user, :email => "user@example.net")
test_sign_in(wrong_user)
end
it "should require matching users for 'edit'" do
get :edit, :id => @user
response.should redirect_to(root_path)
end
it "should require matching users for 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(root_path)
end
end
end
end
describe "DELETE 'destroy'" do
before(:each) do
@user = Factory(:user)
end
describe "as a non-signed-in user" do
it "should deny access" do
delete :destroy, :id => @user
response.should redirect_to(signin_path)
end
end
describe "as a non-admin user" do
it "should protect the page" do
test_sign_in(@user)
delete :destroy, :id => @user
response.should redirect_to(root_path)
end
end
describe "as an admin user" do
before(:each) do
admin = Factory(:user, :email => "admin@example.com", :admin => true)
test_sign_in(admin)
end
it "should destroy the user" do
lambda do
delete :destroy, :id => @user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => @user
response.should redirect_to(users_path)
end
end
end
我的用户控制器方法:
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
flash[:success] = "Profile updated."
redirect_to @user
else
@title = "Edit user"
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
这是我的个工厂.rb
# By using the symbol ':user', we get Factory Girl to simulate the User model.
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl@example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
Factory.sequence :name do |n|
"Person #{n}"
end
Factory.sequence :email do |n|
"person-#{n}@example.com"
end
任何帮助都会非常感激!!
答案 0 :(得分:2)
据我所知,测试运行后你的表格没有被清除。你确定你的测试在退出时清除了桌子吗?通常使用Database Cleaner gem来执行此操作。
问题似乎出现在这行代码中:
@user = Factory(:user)
在您的规范的这一部分:
describe "authentication of edit/update pages" do
before(:each) do
@user = Factory(:user)
end
尝试将其更改为
@user = Factory(:user, :email => "foo@bar.com")
或完全删除它。
在我看来,它嵌套在这个父规范下:
describe "PUT 'update'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
此处在运行"authentication of edit/update pages"
规范之前会创建具有相同电子邮件的用户模型,而在"authentication of edit/update pages"
创建用户时,规范会失败,因为email
应该是唯一的。< / p>
<强>更新强>
我查看了您的规范,看起来您忘记在正确的位置关闭一个区块(并且end
关键字错位了。)
这是正确的规范:
require 'spec_helper'
describe UsersController do
render_views
describe "GET 'index'" do
describe "for non-signed-in users" do
it "should deny access" do
get :index
response.should redirect_to(signin_path)
flash[:notice].should =~ /sign in/i
end
end
describe "for signed-in users" do
before(:each) do
@user = test_sign_in(Factory(:user))
second = Factory(:user, :name => "Bob", :email => "another@example.com")
third = Factory(:user, :name => "Ben", :email => "another@example.net")
@users = [@user, second, third]
30.times do
@users << Factory(:user, :name => Factory.next(:name),
:email => Factory.next(:email))
end
end
it "should be successful" do
get :index
response.should be_success
end
it "should have the right title" do
get :index
response.should have_selector("title", :content => "All users")
end
it "should have an element for each user" do
get :index
@users[0..2].each do |user|
response.should have_selector("li", :content => user.name)
end
end
it "should paginate users" do
get :index
response.should have_selector("div.pagination")
response.should have_selector("span.disabled", :content => "Previous")
response.should have_selector("a", :href => "/users?page=2",
:content => "2")
response.should have_selector("a", :href => "/users?page=2",
:content => "Next")
end
end
end
describe "GET 'show'" do
before(:each) do
@user = Factory(:user)
end
it "should be successful" do
get :show, :id => @user
response.should be_success
end
it "should find the right user" do
get :show, :id => @user
assigns(:user).should == @user
end
it "should have the right title" do
get :show, :id => @user
response.should have_selector("title", :content => @user.name)
end
it "should include the user's name" do
get :show, :id => @user
response.should have_selector("h1", :content => @user.name)
end
it "should have a profile image" do
get :show, :id => @user
response.should have_selector("h1>img", :class => "gravatar")
end
end
describe "GET 'new'" do
it "should be successful" do
get 'new'
response.should be_success
end
it "should have the right title" do
get 'new'
response.should have_selector("title", :content => "Sign up")
end
it "should have a name field" do
get :new
response.should have_selector("input[name='user[name]'][type='text']")
end
it "should have an email field" do
get :new
response.should have_selector("input[name='user[email]'][type='text']")
end
it "should have a password field" do
get :new
response.should have_selector("input[name='user[password]'][type='password']")
end
it "should have a password confirmation field" do
get :new
response.should have_selector("input[name='user[password_confirmation]'][type='password']")
end
end
describe "POST 'create'" do
describe "failure" do
before(:each) do
@attr = {:name => "", :email => "", :password => "",
:password_confirmation => ""}
end
it "should not create a user" do
lambda do
post :create, :user => @attr
end.should_not change(User, :count)
end
it "should have the right title" do
post :create, :user => @attr
response.should have_selector("title", :content => "Sign up")
end
it "should render the 'new' page" do
post :create, :user => @attr
response.should render_template('new')
end
end
describe "success" do
before(:each) do
@attr = {:name => "New User", :email => "user@example.com",
:password => "foobar", :password_confirmation => "foobar"}
end
it "should create a user" do
lambda do
post :create, :user => @attr
end.should change(User, :count).by(1)
end
it "should sign the user in" do
post :create, :user => @attr
controller.should be_signed_in
end
it "should redirect to the user show page" do
post :create, :user => @attr
response.should redirect_to(user_path(assigns(:user)))
end
it "should have a welcome message" do
post :create, :user => @attr
flash[:success].should =~ /welcome to the sample app/i
end
end
end
describe "GET 'edit'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
it "should be successful" do
get :edit, :id => @user
response.should be_success
end
it "should have the right title" do
get :edit, :id => @user
response.should have_selector("title", :content => "Edit user")
end
it "should have a link to change the Gravatar" do
get :edit, :id => @user
gravatar_url = "http://gravatar.com/emails"
response.should have_selector("a", :href => gravatar_url,
:content => "change")
end
end
describe "PUT 'update'" do
before(:each) do
@user = Factory(:user)
test_sign_in(@user)
end
describe "failure" do
before(:each) do
@attr = {:email => "", :name => "", :password => "",
:password_confirmation => ""}
end
it "should render the 'edit' page" do
put :update, :id => @user, :user => @attr
response.should render_template('edit')
end
it "should have the right title" do
put :update, :id => @user, :user => @attr
response.should have_selector("title", :content => "Edit user")
end
end
describe "success" do
before(:each) do
@attr = {:name => "New Name", :email => "user@example.org",
:password => "barbaz", :password_confirmation => "barbaz"}
end
it "should change the user's attributes" do
put :update, :id => @user, :user => @attr
@user.reload
@user.name.should == @attr[:name]
@user.email.should == @attr[:email]
end
it "should redirect to the user show page" do
put :update, :id => @user, :user => @attr
response.should redirect_to(user_path(@user))
end
it "should have a flash message" do
put :update, :id => @user, :user => @attr
flash[:success].should =~ /updated/
end
end
end
describe "authentication of edit/update pages" do
before(:each) do
@user = Factory(:user)
end
describe "for non-signed-in users" do
it "should deny access to 'edit'" do
get :edit, :id => @user
response.should redirect_to(signin_path)
end
it "should deny access to 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(signin_path)
end
end
describe "for signed-in users" do
before(:each) do
wrong_user = Factory(:user, :email => "user@example.net")
test_sign_in(wrong_user)
end
it "should require matching users for 'edit'" do
get :edit, :id => @user
response.should redirect_to(root_path)
end
it "should require matching users for 'update'" do
put :update, :id => @user, :user => {}
response.should redirect_to(root_path)
end
end
end
describe "DELETE 'destroy'" do
before(:each) do
@user = Factory(:user)
end
describe "as a non-signed-in user" do
it "should deny access" do
delete :destroy, :id => @user
response.should redirect_to(signin_path)
end
end
describe "as a non-admin user" do
it "should protect the page" do
test_sign_in(@user)
delete :destroy, :id => @user
response.should redirect_to(root_path)
end
end
describe "as an admin user" do
before(:each) do
admin = Factory(:user, :email => "admin@example.com", :admin => true)
test_sign_in(admin)
end
it "should destroy the user" do
lambda do
delete :destroy, :id => @user
end.should change(User, :count).by(-1)
end
it "should redirect to the users page" do
delete :destroy, :id => @user
response.should redirect_to(users_path)
end
end
end
end
但是,在此更正的规范中,UsersController DELETE 'destroy' as a non-signed-in user should deny access
规范失败,因为实现不正确(假设current_user
永远不会返回nil
,但有时会返回。
更新2 :here可以看到使所有测试通过所需的所有更改。
除了缩进修复之外,唯一需要修复的是admin_user
类中的UsersController
回调:
def admin_user
redirect_to(root_path) unless (current_user && current_user.admin?)
end
答案 1 :(得分:2)
我得到了同样的错误,因为我忘了准备测试数据库:
rake db:test:prepare
答案 2 :(得分:0)
在Listing 10.36中,您是否粘贴了整个代码块来创建管理员用户,而不删除原始块?我在教程中遇到了类似的问题,那是罪魁祸首。
应该是这样的:
<强> LIB /任务/ sample_data.rake 强>
namespace :db do
desc "Fill database with sample data"
task :populate => :environment do
Rake::Task['db:reset'].invoke
admin = User.create!(:name => "Example User",
:email => "example@railstutorial.org",
:password => "foobar",
:password_confirmation => "foobar")
admin.toggle!(:admin)
99.times do |n|
name = Faker::Name.name
email = "example-#{n+1}@railstutorial.org"
password = "password"
User.create!(:name => name,
:email => email,
:password => password,
:password_confirmation => password)
end
end
end