Здравствуйте, записался на курс. При этом ставил галочку на "обучаться с тьютором". На email пришло письмо, о том, что записался на самостоятельное изучение курса. Как выбрать тьютора? |
Войти, выйти
Рендеринг с флэш сообщением
Напомним из Раздела 7.3.3, что мы отображали ошибки регистрации используя сообщения об ошибках модели User. Эти ошибки связаны с конкретным объектом Active Record, но эта стратегия здесь не сработает, поскольку сессии не являются моделью Active Record. Вместо этого, мы поместим сообщение во флеш так чтобы оно отображалось при провальном входе. Первая, немного некорректная попытка представлена в Листинге 8.10.
class SessionsController < ApplicationController def new end def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) # Sign the user in and redirect to the user's show page. else flash[:error] = 'Invalid email/password combination' # Not quite right! render 'new' end end def destroy end endЛистинг 8.10. (Неудачная) попытка обработки провального входа. app/controllers/sessions_controller.rb
Поскольку сообщение об ошибке отображается в шаблоне сайта (Листинге 7.27), сообщение flash[:error] будет автоматически отображено; благодаря Bootstrap CSS, оно, к тому же, будет иметь приятный стиль ( рис. 8.6).
К сожалению, как было отмечено в тексте и в комментарии к Листингу 8.10, этот код не совсем верный. Однако страница выглядит нормально, так в чем же подвох? Проблема заключается в том, что содержимое флэша существует в течение одного запроса, но, в отличие от редиректа (перенаправления) который мы использовали в Листинге 7.28 — повторный рендеринг шаблона с render не считается запросом. В результате флэш сообщение существует на один запрос дольше чем мы хотим. Например, если мы отправим невалидную информацию, флэш сообщение будет установлено и отображено на странице входа ( рис. 8.6); если мы кликнем на другую страницу, такую как Home, что будет первым запросом после отправки формы, то флэш сообщение будет вновь отображено ( рис. 8.7).
Это постоянство флэша является багом нашего приложения и прежде чем приступить к его исправлению, было бы неплохо написать тест отлавливающий эту ошибку. В частности, тест провального входа в данный момент проходит:
$ bundle exec rspec spec/requests/authentication_pages_spec.rb \ > -e "signin with invalid information"
Но тесты ни в коем случае не должны проходить при наличии известной ошибки приложения, так что мы должны добавить провальный тест для ее отлова. К счастью, работа с проблемами вроде неисчезающего флэша, это одна из тех областей, где интеграционные тесты блестяще справляются с поставленной задачей; они позволяют нам сказать именно то, что мы имеем в виду:
describe "after visiting another page" do before { click_link "Home" } it { should_not have_selector('div.alert.alert-error') } end
После отправки невалидных данных, этот тест переходит по Home ссылке, а затем требует отсутствия флэш сообщения об ошибке. Обновленный код с модифицированным тестом флэша показан в Листинге 8.11.
require 'spec_helper' describe "Authentication" do . . . describe "signin" do before { visit signin_path } describe "with invalid information" do before { click_button "Sign in" } it { should have_title('Sign in') } it { should have_selector('div.alert.alert-error') } describe "after visiting another page" do before { click_link "Home" } it { should_not have_selector('div.alert.alert-error') } end end . . . end endЛистинг 8.11. Правильный тест на провальный вход. spec/requests/authentication_pages_spec.rb
Новый тест не проходит, как и требуется:
$ bundle exec rspec spec/requests/authentication_pages_spec.rb \ > -e "signin with invalid information"
Для того чтобы получить прохождение этого провального теста, мы заменим flash на flash.now, который специально создан для отображения флэш сообщения на отрендеренных страницах; в отличие от содержимого flash, его содержимое исчезает сразу после дополнительного запроса. Исправленный код приложения представлен в Листинге 8.12.
class SessionsController < ApplicationController def new end def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) # Sign the user in and redirect to the user's show page. else flash.now[:error] = 'Invalid email/password combination' render 'new' end end def destroy end endЛистинг 8.12. Исправленный код для провального входа. app/controllers/sessions_controller.rb
Теперь набор тестов для пользователей предоставивших невалидные данные для входа должен быть зеленым:
$ bundle exec rspec spec/requests/authentication_pages_spec.rb \ > -e "with invalid information"