2012-01-23 51 views
1

我工作的Rails的教程,並作爲年底按照指示,我總是得到預期的結果,但整理後chapter 10,我得到的波紋錯誤,我無法找到問題是什麼。Rails的教程第10章RSpec的故障由章

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 => "[email protected]", 
       :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 => "[email protected]") 
     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 => "[email protected]", :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 

這裏是我的factories.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     "[email protected]" 
    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 

任何幫助將是GR非常感謝!

回答

2

至於我可以看到測試運行後,你的表沒有被清除。你確定你的測試在退出時清除了桌子嗎?通常數據庫清理器gem用於執行此操作。

的問題似乎與這行代碼:

@user = Factory(:user) 

在規範的這一部分:

describe "authentication of edit/update pages" do 
    before(:each) do 
    @user = Factory(:user) 
    end 

試着改變它

@user = Factory(:user, :email => "[email protected]") 

或將其刪除完全。

在我看來,它的這個父規格下築巢:

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應該是唯一的。

UPDATE:

我看看你的規格,看起來你已經忘記了在正確的地方,關閉塊(和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 => "[email protected]") 
     third = Factory(:user, :name => "Ben", :email => "[email protected]") 

     @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 => "[email protected]", 
       :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 => "[email protected]", 
       :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 => "[email protected]") 
     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 => "[email protected]", :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但有時確實)。

UPDATE 2:使所有測試通過所需的所有更改可以看到here

除了壓痕修復需要修復的唯一的事情就是admin_user回調在UsersController類:

def admin_user 
    redirect_to(root_path) unless (current_user && current_user.admin?) 
end 
+0

我不認爲我已經實現了。你能解釋爲什麼這是必要的嗎? – Vahid

+0

我檢查過,每次測試後數據庫都會清理乾淨。 – Vahid

+0

你可以壓縮你的項目,併發送上傳到某個地方,我會下載它並看看。 – Behrang

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 => "[email protected]", 
        :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 
+0

是的,我的代碼看起來與此相同。 – Vahid

2

我得到了同樣的錯誤,因爲我忘了準備測試數據庫:

rake db:test:prepare 
相關問題