Здравствуйте, записался на курс. При этом ставил галочку на "обучаться с тьютором". На email пришло письмо, о том, что записался на самостоятельное изучение курса. Как выбрать тьютора? |
Обновление, демонстрация и удаление пользователей
Дружелюбная переадресация
Защита наших страниц закончена, как и было написано, но есть один небольшой недостаток: когда пользователи пытаются получить доступ к защищенной странице, они перенаправляются к странице профиля, независимо от того, куда они пытались попасть. Другими словами, если не залогинившийся пользователь пытается посетить страницу редактирования, после входа пользователь будет перенаправлен на /users/1 вместо /users/1/edit. Было бы намного более доброжелательно, по отношению к пользователям, все же перенаправлять их на запрашиваемую страницу вместо этого .
Для того чтобы протестировать такую "дружелюбную переадресацию", мы вначале посещаем страницу редактирования пользователя, которая перенаправит нас на страницу входа. Затем мы введем валидную информацию для входа и кликнем по кнопке "Sign in". Результирующей страницей, которой по дефолту является профиль пользователя, в данном случае должна быть страница "Edit user". Тест для этой последовательности представлен в Листинге 9.16.
require 'spec_helper' describe "Authentication" do . . . describe "authorization" do describe "for non-signed-in users" do let(:user) { FactoryGirl.create(:user) } describe "when attempting to visit a protected page" do before do visit edit_user_path(user) fill_in "Email", with: user.email fill_in "Password", with: user.password click_button "Sign in" end describe "after signing in" do it "should render the desired protected page" do expect(page).to have_title('Edit user') end end end . . . end . . . end endЛистинг 9.16. Тест для дружелюбной переадресации. spec/requests/authentication_pages_spec.rb
Теперь реализация.4Код в этом разделе это адаптация (переделка) гема Clearance команды разработчиков thoughtbot Для того чтобы перенаправить пользователей к запрашиваемой ими странице, нам нужно где-то сохранить запрашиваемую страницу, а затем переадресовать к ней. Мы добьемся этого с помощью пары методов, store_location и redirect_back_or, определенных в хелпере Sessions (Листинг 9.17).
module SessionsHelper . . . def redirect_back_or(default) redirect_to(session[:return_to] || default) session.delete(:return_to) end def store_location session[:return_to] = request.url if request.get? end endЛистинг 9.17. Код реализующий дружественную переадресацию. app/helpers/sessions_helper.rb
В роли механизма хранения выступает объект session предоставляемый Rails, о котором вы можете думать как об экземпляре переменной cookies из Раздела 8.2.1 которая автоматически истекает при закрытии браузера. Мы также используем объект request для получения url, т.e. URL запрашиваемой страницы. Метод store_location помещает запрашиваемый URL в переменную session под ключом :return_to, но только для GET запроса (if request.get?). Это предотвращает сохранение URL для перенаправления если пользовател, скажем, отправляет форму не будучи залогиненым (что, пусть и является крайним случаем, но все же может случиться если, например, пользователь удалил remember token вручную перед отправкой формы); в данном случае, результирующий редирект выдаст GET запрос к URL ожидающему POST, PATCH или DELETE, что приведет к ошибке.5
Для того чтобы использовать store_location, нам необходимо добавить ее в предфильтр signed_in_user, как это показано в Листинге 9.18.
class UsersController < ApplicationController before_action :signed_in_user, only: [:edit, :update] before_action :correct_user, only: [:edit, :update] . . . def edit end . . . private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end # Before filters def signed_in_user unless signed_in? store_location redirect_to signin_url, notice: "Please sign in." end end def correct_user @user = User.find(params[:id]) redirect_to(root_url) unless current_user?(@user) end endЛистинг 9.18. Добавление store_location в предфильтр :signed_in_user. app/controllers/users_controller.rb
Для того чтобы реализовать саму переадресацию, мы используем метод redirect_back_or для перенаправления на запрашиваемый URL если он существует или на какой-либо дефолтный URL в противном случае, который мы добавим в действие create контроллера Sessions для переадресации после успешного входа (Листинг 9.19). Метод redirect_back_or использует оператор "или" ||
session[:return_to] || default
Этот код оценивает session[:return_to] и до тех пор, пока оно не является nil, в противном случае он оценивает заданный дефолтный URL. Обратите внимание, что Листинг 9.17 заботится об удалении URL перенаправления; в противном случае, последующие попытки входа перенаправлялись бы на защищенную страницу до тех пор, пока пользователь не закроет браузер. (Тестирование этого поведения оставлено в качестве упражнения (Раздел 9.6.)
class SessionsController < ApplicationController . . . def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) sign_in user redirect_back_or user else flash.now[:error] = 'Invalid email/password combination' render 'new' end end . . . endЛистинг 9.19. Действие create контроллера Sessions с дружелюбной переадресацией. app/controllers/sessions_controller.rb
(Если вы выполнили первое упражнение в Главае 8, убедитесь в том что вы используете правильный хэш params в Листинге 9.19.)
С этим интеграционные тесты дружелюбной переадресации из Листинга 9.16 должны пройти и базовая аутентификация и защита страниц могут считаться законченными. Как обычно, прежде чем продолжать, хорошо бы проверить что набор тестов зеленый:
$ bundle exec rspec spec/