注意:我已经阅读了这个问题和答案,但由于某种原因,代码对我不起作用。(见下文我得到的错误)
Rails 教程第 9 章中的练习 10 要求您: 修改 [for users] 的 destroy 操作以防止管理员用户销毁自己。(先写一个测试。)
这里棘手的部分是测试它,因为应用程序已经为当前用户隐藏了“删除”链接,所以你必须直接进行 http 请求。
我让代码正常工作,并通过删除隐藏当前用户的删除链接的代码来测试它。果然,如果我单击当前登录用户的删除链接,它会重定向我并给我通知消息。
来自 users_controller.rb
def destroy
@user = User.find(params[:id])
if current_user?(@user)
redirect_to users_path, notice: "You can't destroy yourself."
else
@user.destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
end
我遇到的问题是为此编写测试,将发送删除请求并调用销毁方法。我尝试了Rspec 测试中的解决方案,如果没有删除链接就销毁,我在这里复制:
来自 user_pages_spec.rb
describe "destroy" do
let(:admin) { FactoryGirl.create(:admin) }
it "should not allow the admin to delete herself" do
sign_in admin
#expect { delete user_path(admin), method: :delete }.should change(User, :count)
expect { delete :destroy, :id => admin.id }.should_not change(User, :count)
end
end
但是当我运行这个时,我从 RSpec 得到这个错误
Failures:
1) User Pages destroy should not allow the admin to delete herself
Failure/Error: expect { delete :destroy, :id => admin.id }.should_not change(User, :count)
ArgumentError:
bad argument (expected URI object or URI string)
# ./spec/requests/user_pages_spec.rb:180:in `block (4 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:180:in `block (3 levels) in <top (required)>'
所以,我的问题是:1)为什么上面的代码失败了?2)如何模拟“删除”以在我的控制器中调用销毁操作?
环境:Mac OSX ruby 1.9.3p194 Rails 3.2.3
用于测试的宝石:
组 :test do gem 'rspec-rails', '2.9.0' gem 'capybara', '1.1.2' gem 'rb-fsevent', '0.4.3.1', :require => false gem '咆哮','1.0.3'宝石'guard-spork','0.3.2'宝石'spork','0.9.0'宝石'factory_girl_rails','1.4.0'结束
更多信息 我已经尝试了很多方法来尝试模拟单击删除链接,但似乎都没有。我一直在使用调试器 gem 来查看是否调用了 destroy 方法。在单击链接以删除其他用户的测试中,destroy 方法被调用并且工作正常:
it "should be able to delete another user" do
expect { click_link('delete') }.to change(User, :count).by(-1)
end
但是我没有尝试直接生成删除请求来调用destroy方法。
谢谢你的帮助!
将要
** 更新 **
我尝试了 DVG 的建议:
describe "destroy" do
let(:admin) { FactoryGirl.create(:admin) }
it "should not allow the admin to delete herself" do
sign_in admin
#expect { delete user_path(admin), method: :delete }.should change(User, :count)
expect { delete :destroy, :id => admin }.to_not change(User, :count)
end
end
并得到这个错误:
6) User Pages destroy should not allow the admin to delete herself
Failure/Error: expect { delete :destroy, :id => admin }.to_not change(User, :count)
ArgumentError:
bad argument (expected URI object or URI string)
# ./spec/requests/user_pages_spec.rb:190:in `block (4 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:190:in `block (3 levels) in <top (required)>'
解决方案
我在 FOREVER 之后想通了。
我不得不使用 Rack::Test 来发出 DELETE 请求,但是 Capybara 和 Rack::Test 不共享相同的 MockSession,所以我不得不拉入 :remember_token 和 :!sample_app_session cookie 并将它们放入 DELETE 请求中手动。这是有效的。(下面列出的另一个问题是我有一个 force_ssl 语句,它没有让我的破坏操作被调用。
describe "destroy" do
let!(:admin) { FactoryGirl.create(:admin) }
before do
sign_in admin
end
it "should delete a normal user" do
user = FactoryGirl.create(:user)
expect { delete user_path(user), {},
'HTTP_COOKIE' => "remember_token=#{admin.remember_token},
#{Capybara.current_session.driver.response.headers["Set-Cookie"]}" }.
to change(User, :count).by(-1)
end
it "should not allow the admin to delete herself" do
expect { delete user_path(admin), {},
'HTTP_COOKIE' => "remember_token=#{admin.remember_token},
#{Capybara.current_session.driver.response.headers["Set-Cookie"]}" }.
to_not change(User, :count)
end
end
在我的 users_controller.rb 中的 before_filters 之后,我有一个 force_ssl 语句,这以某种方式把事情扔掉了,所以我从来没有去破坏行动。
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:edit, :update, :index]
before_filter :existing_user, only: [:new, :create]
before_filter :correct_user, only: [:edit, :update]
before_filter :admin_user, only: :destroy
#force_ssl
def index
@users = User.paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
@microposts = @user.microposts.paginate(page: params[:page])
end
def destroy
@user = User.find(params[:id])
if current_user?(@user)
redirect_to users_path, notice: "You can't destroy yourself."
else
@user.destroy
flash[:success] = "User destroyed."
redirect_to users_path
end
end
这些有助于找到解决方案
https://gist.github.com/484787
http://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles/