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

Войти, выйти

Вход после регистрации

В принципе, хотя мы закончили с аутентификацией, вновь зарегистрированные пользователи могут оказаться сбитыми с толку, так как они не вошли в систему по умолчанию. Реализация этого - последний штрих который мы добавим прежде чем позволим пользователям входить на наш сайт. Мы начнем с добавления строки к тестам аутентификации (Листинг 8.26). Это включает "after saving the user" describe блок из Листинга 7.32 (Раздел 7.6), который вы должны добавить в тест, если вы не сделали этого в соответствующем упражнении

require 'spec_helper'

describe "User pages" do
    .
    .
    .
    describe "with valid information" do
      .
      .
      .
      describe "after saving the user" do
        before { click_button submit }
        let(:user) { User.find_by(email: 'user@example.com') }

        it { should have_link('Sign out') }
        it { should have_title(user.name) }
        it { should have_selector('div.alert.alert-success', text: 'Welcome') }
      end
    end
  end
end
Листинг 8.26. Тестирование того, что вновь зарегистрированные пользователи также являются вошедшими. spec/requests/user_pages_spec.rb

Здесь мы протестировали появление ссылки на выход для того чтобы убедиться что пользователь успешно вошел после регистрации.

С методом sign_in из Раздела 8.2, получение прохождения этого теста фактически впустив пользователя в систему легко: просто добавим sign_in @user сразу после сохранения пользователя в базе данных (Листинг 8.27).

class UsersController < ApplicationController
  .
  .
  .
  def create
    @user = User.new(user_params)
    if @user.save
      sign_in @user
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end
  .
  .
  .
end
Листинг 8.27. Вход пользователя сразу после регистрации. app/controllers/users_controller.rb

Выход

Как обсуждалось в Разделе 8.1, наша аутентификационная модель предполагает сохранение пользователей вошедшими до тех пор, пока они явно не выйдут из системы. В этом разделе мы добавим эту, необходимую нам и пользователям, возможность выхода.

До сих пор действия контроллера Sessions следовали RESTful конвенции, используя new для страницы входа и create для его завершения. Мы продолжим эту тему используя действие destroy для удаления сессий, т.е., для выхода. Для того чтобы протестировать это, мы кликнем по ссылке "Sign out" а затем попробуем найти вновь появившуюся ссылку на вход (Листинг 8.28).

require 'spec_helper'

describe "Authentication" do
  .
  .
  .
  describe "signin" do
    .
    .
    .
    describe "with valid information" do
      .
      .
      .
      describe "followed by signout" do
        before { click_link "Sign out" }
        it { should have_link('Sign in') }
      end
    end
  end
end
Листинг 8.28. Тест выхода пользователя. spec/requests/authentication_pages_spec.rb

Как и со входом пользователя, основанном на функции sign_in, выход пользователя просто перекладывает работу на функцию sign_out (Листинг 8.29).

class SessionsController < ApplicationController
  .
  .
  .
  def destroy
    sign_out
    redirect_to root_url
  end
end
Листинг 8.29. Уничтожение сессии (выход пользователя). app/controllers/sessions_controller.rb

Как и другие элементы аутентификации, мы поместим sign_out в вспомогательный модуль Sessions. Листинг 8.30 показывает шаги: мы вначале меняем remember token пользователя в базе данных (на тот случай если куки были украдены, поскольку в этом случае они могут быть использованы для авторизации пользователя), затем мы вызываем метод delete на куках для удаления remember token из сессии; в качестве необязательного шага, мы устанавливаем текущего пользователя равным nil. (Как и назначение в методе sign_in (Листинг 8.19), установка текущего пользователя равным nil в настоящий момент не является строгой необходимостью из-за незамедлительного редиректа в действии destroy, но все же это хорошая идея - на случай если мы когда-либо захотим использовать sign_out без редиректа.)

module SessionsHelper

  def sign_in(user)
    remember_token = User.new_remember_token
    cookies.permanent[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.encrypt(remember_token))
    self.current_user = user
  end
  .
  .
  .
  def sign_out
    current_user.update_attribute(:remember_token,
                                  User.encrypt(User.new_remember_token))
    cookies.delete(:remember_token)
    self.current_user = nil
  end
end
Листинг 8.30. Метод sign_out в модуле Sessions хелпер. app/helpers/sessions_helper.rb

Это завершает триумвират регистрация/вход/выход и набор тестов должен пройти:

$ bundle exec rspec spec/

Стоит отметить, что наш набор тестов покрывает большую часть механизма аутентификации, но не все же не полностью. Например, мы не тестируем то как долго живет "remember me" куки и даже не тестируем устанавливается ли она вообще. Это возможно сделать, но практика показывает, что непосредственное тестирование значения куки является хрупким и имеет тенденцию зависеть от деталей реализации которые иногда меняются от одного релиза Rails к другому. Результатом служат рухнувшие тесты вполне себе рабочего кода. Фокусируясь на функционале верхнего уровня - проверяя что пользователи могут войти, оставаться вошедшими при переходе от страницы к странице и могут выйти - мы тестируем ядро кода приложения не заморачиваясь менее важными деталями.

Вадим Обозин
Вадим Обозин

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