私は Rails チュートリアルの第 10 章の演習に取り組んでおり、管理者ユーザーが自分自身を削除できないようにする演習で問題が発生しました。私の最初のアイデアは、単純に現在のユーザーの ID をチェックし、それを params[:id] と比較して、それらが等しくないことを確認することでした。Users コントローラーでの破棄アクションは次のようになりました。
def destroy
if current_user.id == params[:id].to_i
flash[:notice] = "You cannot delete yourself."
else
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
end
redirect_to users_path
end
これは、アプリで手動でテストすると完全に機能しますが、3 つの RSpec テストが同じ「undefined method 'to_i'」エラーで失敗します (以下を参照)。
1) UsersController DELETE 'destroy' as an admin user should destory the user
Failure/Error: delete :destroy, :id => @user
NoMethodError:
undefined method `to_i' for #<User:0x000001032de188>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:310:in `block (5 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:309:in `block (4 levels) in <top (required)>'
2) UsersController DELETE 'destroy' as an admin user should redirect to the users page
Failure/Error: delete :destroy, :id => @user
NoMethodError:
undefined method `to_i' for #<User:0x000001032b5850>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:315:in `block (4 levels) in <top (required)>'
3) UsersController DELETE 'destroy' as an admin user should not allow you to destroy self
Failure/Error: delete :destroy, :id => @admin
NoMethodError:
undefined method `to_i' for #<User:0x0000010327e350>
# ./app/controllers/users_controller.rb:48:in `destroy'
# ./spec/controllers/users_controller_spec.rb:321:in `block (5 levels) in <top (required)>'
# ./spec/controllers/users_controller_spec.rb:320:in `block (4 levels) in <top (required)>'
params[:id] を使用してユーザーを見つけ、以下のように current_user と比較すると、アプリと RSpec の両方で機能します。
def destroy
if current_user == User.find(params[:id])
flash[:notice] = "You cannot delete yourself."
else
User.find(params[:id]).destroy
flash[:success] = "User destroyed."
end
redirect_to users_path
end
「to_i」メソッドでRSpecに問題があるのはなぜですか? データベースを「検索」するのではなく、現在のユーザーIDを削除対象のユーザーのIDと単純に比較するのが最善だと思ったので、誰かが私がそのアプローチに傾倒していたのを不思議に思っているなら(params [:id]を介して)ユーザー。
参考までに、これは私の RSpec テストです。
describe "DELETE 'destroy'" do
before(:each) do
@user = Factory(:user)
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 destory 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
it "should not allow you to destroy self" do
lambda do
delete :destroy, :id => @admin
end.should change(User, :count).by(0)
response.should redirect_to(users_path)
flash[:notice].should =~ /cannot delete yourself/
end
end
end
どんな助けでも大歓迎です!