Примечание :Я прочитал этот вопрос и ответ, но по какой-то причине код у меня не работает. (см. ниже ошибку, которую я получаю)
Упражнение 10 из Главы 9 Учебника по Rails просит вас :Изменить действие уничтожения [для пользователей], чтобы пользователи-администраторы не могли уничтожить себя. (Сначала напишите тест.)
Сложность здесь заключается в том, чтобы протестировать его, потому что приложение уже скрывает ссылку «удалить» для текущего пользователя, поэтому вам нужно выполнить HTTP-запрос напрямую.
Я заставил код работать и протестировал его, удалив часть кода, которая скрывает ссылку удаления для текущего пользователя. Конечно,если я нажимаю на ссылку удаления для текущего пользователя -, он перенаправляет меня и дает мне уведомление.
От пользователей _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 test для уничтожения, если нет ссылки на удаление , которое я копирую здесь:
Из пользовательских _страниц _спец.рб
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 '
#./spec/requests/user_pages_spec.rb:180:in `block (3 levels) in '
Итак, мои вопросы :1 )Почему приведенный выше код не работает? 2 )Как имитировать «удаление», чтобы вызвать действие уничтожения в моем контроллере?
Окружающая среда :Mac OS X рубин 1.9.3p194 Рельсы 3.2.3
Драгоценные камни для тестирования:
группа :тест делать gem 'rspec -рельсы', '2.9.0' драгоценный камень «капибара», «1.1.2» gem 'rb -fsevent', '0.4.3.1', :требуют => ложь драгоценный камень «рычание», «1.0.3» драгоценный камень 'охрана -спорк', '0.3.2' гем 'спорк', '0.9.0' gem 'фабрика _девушка _рельсы', '1.4.0' конец
Подробнее Я пробовал тонну способов, чтобы попытаться имитировать нажатие на ссылку удаления, и ни один из них не работает. Я использовал драгоценный камень отладчика, чтобы увидеть, вызывается ли метод уничтожения. В тесте, который щелкает ссылку для удаления другого пользователя, вызывается метод уничтожения, и он работает нормально:
it "should be able to delete another user" do
expect { click_link('delete') }.to change(User, :count).by(-1)
end
Но ничто из того, что я пытался сгенерировать запрос на удаление напрямую, не помогло вызвать метод уничтожения.
Спасибо за вашу помощь!
Уилл
**ОБНОВЛЕНИЕ**
Я попробовал предложение 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 '
#./spec/requests/user_pages_spec.rb:190:in `block (3 levels) in '
РЕШЕНИЕ
Я понял это после FOREVER.
Мне пришлось использовать Rack ::Test для выдачи запроса DELETE, но Capybara и Rack ::Test не используют один и тот же MockSession, поэтому мне пришлось вытащить токен :запомнить _и :!sample _приложение _файлы 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
У меня было выражение force _ssl после моих фильтров before _в моих пользователях _controller.rb, и это каким-то образом сбивало ситуацию, поэтому я так и не добрался до действия уничтожения.
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/