Опубликован: 27.01.2016 | Доступ: свободный | Студентов: 916 / 58 | Длительность: 23:07:00
Лекция 8:

Войти, выйти

Рендеринг с флэш сообщением

Напомним из Раздела 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.6. Флэш сообщение для провального входа.

К сожалению, как было отмечено в тексте и в комментарии к Листингу 8.10, этот код не совсем верный. Однако страница выглядит нормально, так в чем же подвох? Проблема заключается в том, что содержимое флэша существует в течение одного запроса, но, в отличие от редиректа (перенаправления) который мы использовали в Листинге 7.28 — повторный рендеринг шаблона с render не считается запросом. В результате флэш сообщение существует на один запрос дольше чем мы хотим. Например, если мы отправим невалидную информацию, флэш сообщение будет установлено и отображено на странице входа ( рис. 8.6); если мы кликнем на другую страницу, такую как Home, что будет первым запросом после отправки формы, то флэш сообщение будет вновь отображено ( рис. 8.7).

Пример ненужного постоянства флэш сообщения.

Рис. 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"
Вадим Обозин
Вадим Обозин

Здравствуйте, записался на курс. При этом ставил галочку на "обучаться с тьютором". На email пришло письмо, о том, что записался на самостоятельное изучение курса. Как выбрать тьютора?