2012-06-06 59 views
3

我正在經歷railstutorial.org最新的rails教程,我被困在某個練習(#http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-users#sec:updating_deleting_exercises#8)。你必須寫一個rspec /水豚測試,以確保管理員不能刪除自己。我的實施工作正常,但無法讓測試正常工作。這是我的代碼。我在這裏發現了類似的問題:Ruby on Rails syntaxhttps://getsatisfaction.com/railstutorial/topics/how_to_prevent_admin_user_from_deleting_themselves。但我認爲這是一個較老的教程,而不是同一個問題。Rspec測試銷燬,如果沒有刪除鏈接

這裏是投機/請求/ user_pages_spec.rb相關代碼:

describe "User pages" do 
    subject { page } 
    describe "delete links" do 
     describe "as an admin user" do 
     let(:admin) { FactoryGirl.create(:admin) } 
     before do 
      sign_in admin 
      visit users_path 
     end 
     it "should not be able to delete themself" do 
      expect { admin.delete }.should_not change(User, :count) 
     end 
     end 
    end 
    end 
end 

該錯誤消息說,用戶數量是越來越1。

爲了完整降低,這是我的(工作)執行:

class UsersController < ApplicationController 
    before_filter :current_admin,  only: :destroy 
    def current_admin 
    @user = User.find(params[:id]) 
    redirect_to users_path, notice: "Cannot delete current admin" if current_user?(@user) 
    end 
end 

我在哪裏出錯了,謝謝? (我遺漏了一些方法,但希望有足夠的知道我想要做什麼)

編輯:使用Ruby v1.9.3,Rails v3.2.3。默認情況下,管理員沒有刪除鏈接。

EDIT2:這裏是我的工作:

規格/控制器/ users_controller_spec.rb

require 'spec_helper' 

describe UsersController do 
    describe "admins" do 
    let(:admin) { FactoryGirl.create(:admin) } 

    it "should not be able to delete themself" do 
     sign_in admin 
     expect { delete :destroy, :id => admin.id }.should_not change(User, :count) 
    end 
    end 
end 

users_controller.rb

def destroy 
    @user = User.find(params[:id]) 

    if current_user?(@user) 
    flash[:error] = "Cannot delete current admin" 
    else 
    @user.destroy 
    flash[:success] = "User destroyed." 
    end 
    redirect_to users_path 
end 

回答

7

您的before_filter的語法不正確。該電話應該看起來像這樣

before_filter :current_admin, :only => [:destroy] 

你也可能會更好地保持這種邏輯的銷燬行動。由於它只適用於該行動,我不認爲有任何理由將其移入單獨的方法/過濾器。你指出的其他問題,其實都是從舊版本的教程,但邏輯仍然是相同的:

class UsersController < ApplicationController 
    def destroy 
    @user = User.find(params[:id]) 

    if current_user?(@user) 
     flash[:error] = "Cannot delete current admin" 
    else 
     user.destroy 
     flash[:notice] = "User was successfully deleted" 
    end 

    redirect_to users_path 
    end 
end 

至於你的測試中,它的失敗,因爲你所呼叫的刪除方法,而不是破壞行動在你的控制器中。從ActiveRecord::Relation

的Active Record對象不實例化,所以對象的回調 不被執行,包括任何:依賴關聯選項或 觀測方法。

因爲他們要求您使用rspec/capybara,您可以使用click_link方法觸發銷燬操作。由於您位於包含多個列表的索引頁面上,因此您應該查看Capybara::Node::Finders以便可靠地選擇正確的按鈕。

編輯:既然你正在尋找測試控制器,不看,你可以測試:

describe "admins" do 
    let(:admin) { FactoryGirl.create(:admin) } 

    it "should not be able to delete themself" do 
    sign_in admin 
    expect { delete :destroy, :id => admin.id }.should_not change(User, :count) 
    end 
end 
+0

感謝您的回覆。我會玩弄你的答案,看看它是否有效。但是,默認情況下,管理員的銷燬操作沒有鏈接。所以我不認爲我可以使用click_link方法。另外,當我爲管理員添加刪除鏈接時,爲了測試我的控制器,我的before_filter正在工作。但是,這可能不是最好的辦法。我在想,我的主題可能不正確,因爲我沒有真正測試頁面,而是控制器。 –

+0

你可以使用「delete:destroy」直接調用你的銷燬行爲。我在回答中添加了一個示例 – rpedroso

+0

current_user方法不存在以用於測試。也許我應該寫一個。有沒有使用管理對象的另一種方式?我應該將添加的測試移動到不同的文件,如spec/controllers/users_controller_spec.rb嗎? –

7

這可以在幾乎是railstutorial.org書似乎什麼user_pages_spec測試希望你能做到。 (Ruby on Rails教程第9章練習9)。無論這是一個好主意,我都會留下更深刻的印象。

在user_pages_spec.rb測試代碼應該是這樣的:

describe "I should not be able to delete admins" do 
     before { delete user_path(admin.id) } 

     it { should_not have_selector('div.alert.alert-error', text: 'Admins cannot delete themselves') } 
    end 

刪除user_path(admin.id)將模仿單擊「刪除」,並在RSpec中,水豚的作品。這將通過您的控制器代碼,假設您更改錯誤消息以匹配我的或反之亦然。

此外,UsersController中的before_filter語法似乎可以在有或沒有[]的情況下工作,如果只有項目。

+2

測試是否有錯誤消息看起來很脆弱。正如你暗示,如果我改變了字符串,忘記更新測試,那會導致誤報。對我來說更有意義的東西更像是:'expect {delete user_path(admin.id)} .should_not change(User,:count)' –