0

我正在关注 Michael Hartl 关于 Ruby on Rails 的优秀教程。我一直试图理解ActionDispatch::Response的工作方式。这源自第 9 章的练习 9(Rails 版本 3.2.3)。

特别是我们被要求确保管理员用户不能自己User#destroy。我有一个想法如何做到这一点,但由于我试图遵循 TDD 方法,所以我首先编写测试。

这是我测试中的相关片段:

describe "authorization" do
    describe "as non-admin user" do
        let(:admin) {FactoryGirl.create(:admin)}
        let(:non_admin) {FactoryGirl.create(:user)}

        before{valid_signin non_admin}

        describe "submitting a DELETE request to the Users#destroy action" do
            before do
                delete user_path(admin)
                #puts response.message
                puts response.succes?
            end
            specify{ response.should redirect_to(root_path) }
            specify{ response.should_not be_success }
        end
    end
    #Exercise 9.6-9 prevent admin from destroying himself
    describe "as admin user" do
        let(:admin){FactoryGirl.create(:admin)}
        let(:non_admin){FactoryGirl.create(:user)}

        before do 
            valid_signin admin
        end
        it "should be able to delete another user" do
            expect { delete user_path(non_admin) }.to change(User, :count).by(-1)
        end

        describe "can destroy others" do
            before do 
                puts admin.admin?
                delete user_path(non_admin)
                puts response.success?
            end
            #specify{response.should be_success}
            specify{response.should_not be_redirect}
        end 

        describe "cannot destroy himself" do
            before do
                delete user_path(admin)
                puts response.success?
            end
            #specify{response.should_not be_success}
            specify{response.should be_redirect}
        end 
    end

.
.
.
end

除测试外,所有测试均通过"can destroy others"

但是,如果我puts response.success?在每个delete请求之后,我总是得到False,所以没有一个请求“成功”。

手动与 webapp 交互并删除用户工作得很好,所以我认为这response.success并不意味着detroy(或任何与此相关的请求)不成功,而是其他事情。我读到它与HTTP 响应 200/302/400之间的区别有关,但我并不完全确定。

作为记录,这是我的User#destroy

def destroy
    User.find(params[:id]).destroy
    flash[:success]="User destroyed."
    redirect_to users_path
end

对此有任何启示吗?谢谢!

编辑

这是我的工厂:

FactoryGirl.define do
    factory :user do
        sequence(:name){ |n| "Person #{n}" }
        sequence(:email){ |n| "person_#{n}@example.com"}
        password "foobar"
        password_confirmation "foobar"

        factory :admin do
            admin true
        end
    end

end

按照@Peter Alfvin 的建议编辑 2 ,我更改了行

let(:user){FactoryGirl.create(:user)}

let(:admin){FactoryGirl.create(:admin)}

总的来说。user_ admin我还在请求puts admin.admin?之前添加了一个。delete还是行不通!

编辑 3

将测试更改"can destroy others"为:

describe "can destroy others" do
  before do 
    puts admin.admin?
    delete user_path(non_admin)
    puts response.success?
  end

  #specify{response.should be_success}
  specify{response.should_not be_redirect}

end

似乎也没有帮助。

4

3 回答 3

1

response.success 确实是指 HTTP 响应代码。默认情况下,我相信这是 200 范围内的任何值。redirect_to 在 300 范围内。

于 2013-09-24T19:55:08.590 回答
1

对于您的“管理员”情况,您仍然以“普通”用户而不是管理员用户身份创建和登录,这就是您无法摧毁其他任何人的原因。

于 2013-09-24T19:51:57.463 回答
0

确保您的用户工厂包含此行

factory :user do
  #your user factory code
  factory :admin do 
    admin true
  end
end

然后FactoryGirl.create(:admin)将返回一个管理员用户,或者您也可以使用user.toggle!(:admin)它将标准用户切换为管理员用户。

试试这个

describe "as admin user" do
    let(:admin){FactoryGirl.create(:admin)}
    let(:non_admin){FactoryGirl.create(:user)}

    before do 
        valid_signin admin
    end
    it "should be able to delete another user" do
        expect { delete user_path(non_admin) }.to change(User, :count).by(-1)
    end

    it "can destroy others" do  #
        before do 
            puts admin.admin?
            delete user_path(non_admin)
            puts response.success?
        end
        #specify{response.should be_success}
        specify{response.should_not be_redirect}
    end 

    it "cannot destroy himself" do
        before do
            delete user_path(admin)
            puts response.success?
        end
        #specify{response.should_not be_success}
        specify{response.should be_redirect}
    end 
end

describe 创建了一个魔术类,据我了解,它成为 describe 类的子类。Rails 有很多这样的魔力,它可能会让人感到困惑。此外,我还没有看到您的控制器,但是当您销毁用户时您期望发生什么,因为如果您按照教程进行操作,那么将delete通过浏览器发送重定向将调用您的destroy方法,UsersController教程中有这一行redirect_to users_url,所以response.should_not be_redirect会总是失败,因为规范是错误的而不是控制器。

于 2013-09-24T20:35:57.300 回答