Начало работы с надежной аутентификацией в Rails

12 января 2018

В этой статье мы будем использовать restful_authentication для добавления пользовательской системы в простое приложение Rails. Это отлично подходит для тех, кто впервые начал работу, и вам нужны пошаговые инструкции для использования этого удивительного плагина. В конце статьи посетители смогут создать учетную запись, сбросить пароль, войти в систему, выйти из системы и проверить адреса электронной почты.

Основы

Эта часть учебника очень проста. Все, что мы сделаем, это создать простое приложение, которое позволяет пользователям создавать обновление для чтения, уничтожая запись, содержащую имя и рейтинг фильма. Я рекомендую продвинутым разработчикам Rails перейти к третьему разделу, где начинается код restful_authentication. Примечание. Я сделал все это в OSX на Mac, но это не зависит от платформы, хотя вам может потребоваться добавить. для некоторых команд, так что Windows знает, что вы ищете в текущем каталоге. Если у вас есть какие-либо проблемы, я могу помочь в комментариях или в twitter (@noahhendrix)

Сгенерировать приложение

Сначала нам нужно, чтобы рельсы генерировали код рамки. Это делается путем выполнения «rails MyMovies» в терминале. «MyMovies» - это то, что я выбрал, чтобы назвать это приложение, и вы можете использовать это или что-то еще. Эта команда создает много файлов и папок, большинство из которых нам неинтересны, но они необходимы для правильной работы приложения. После этого он захочет перейти во вновь созданный каталог MyMovies.

rails MyMovies
cd MyMovies

Сгенерируйте модель фильма

Теперь мы собираемся использовать генераторы Rails для быстрого создания кода и базы данных для нашего основного приложения. В терминале выполните команду:

script/generate scaffold Movie title:string rating:integer

Здесь мы говорим рельсы, что мы хотим, чтобы код сгенерировал обработку модели «Movie», которая в качестве заголовка строки и целочисленного рейтинга. Обратите внимание, что это приведет к созданию еще нескольких файлов, одним из которых является миграция базы данных. Здесь волшебство рельсов действительно показывает себя, но сначала мы должны перенести базу данных.

rake db:migrate

Эта команда настроит базу данных и создаст таблицу с соответствующими столбцами. Примечание. Рельсы достаточно умны, чтобы включать в себя столбцы ID, created_at и updated_at. Он также будет управлять этими столбцами, чтобы разработчикам никогда не приходилось писать код, который устанавливает эти столбцы. Теперь давайте посмотрим на плоды нашего труда, верно, что мы написали нулевые строки кода, но у нас уже есть рабочее приложение. Запустите сервер и перейдите на http: localhost: 3000 фильмов. В вашем терминальном типе:

script/server

Усовершенствования

Вы можете попытаться создать фильм и рейтинг и посмотреть, как легко все работает. Команда rails действительно сделала отличную работу, позволяющую разработчикам быстро вывести код с минимальными усилиями, однако этот код является лишь отправной точкой. Разработчики должны сделать это самостоятельно и добавить дополнительные функции и настройки для пользователей. Хорошее место для начала - решить, есть ли какие-либо ограничения, которые мы поместим на нашей модели. В этом примере я решил, что мы будем требовать, чтобы пользователь мог оценивать фильм между 1 и 5 звездами. Хотя есть и другие, такие как удостовериться, что они входят в название фильма и что рейтинг - это число. Так обрабатывается в файле модели фильма.

# app/models/movie.rb
validates_presence_of :title, :rating
validates_numericality_of :rating, :greater_than_or_equal_to => 1, :less_than_or_equal_to => 5

Синтаксис, используемый в Rails, часто является подробным, но довольно описательным. Однако положительный побочный эффект заключается в том, что мы никогда не должны угадать, что означает код, который мы пишем. Мы рассказываем рельсы, прежде чем они сохраняются в базе данных, чтобы проверить, что оба заголовка и рейтинг установлены, а в качестве дополнительного рейтинга ограничения должно быть число от 1 до 5. Обратите внимание, что на приведенных ниже изображениях мы создаем сообщение об ошибке по умолчанию в рельсах,

Осознание пользовательского интерфейса

Даже в качестве разработчиков мы не освобождаемся от рассмотрения интерфейса приложений, которые мы разрабатываем. Пользователи должны немедленно понять цель любой информации, отображаемой для них. В нашем приложении мы установили рейтинг, но мы никогда не говорим, что оно должно быть целым числом от 1 до 5. Сначала пользователь может ввести строку, такую как «хорошая». Мы можем поместить ярлык рядом с текстовым полем, в котором перечислены наши требования, но мы можем сделать еще один шаг и явно разрешить им выбирать между параметрами, которые мы хотим в формате радиокнопки. Часть методологии управления представлением модели (MVC) рельсов говорит нам, что это изменение вида, и оно находится в каталоге представлений. Сначала мы должны удалить строку, которая создает текстовое поле и его метку, по строке 11 в моем коде. Искать:

# app/views/movies/edit.html.erb
# app/views/movies/new.html.erb
<%= f.text_field :rating %>

Теперь новый новый код должен быть добавлен как к новым, так и к редактируемым файлам, потому что оба содержат формы, в которых модифицирована модель.

# app/views/movies/edit.html.erb
# app/views/movies/new.html.erb
Rating<br />
<%= f.radio_button  :rating, 1 %> <%= f.label :rating_1, "1" %>
<%= f.radio_button  :rating, 2 %> <%= f.label :rating_2, "2" %>
<%= f.radio_button  :rating, 3 %> <%= f.label :rating_3, "3" %>
<%= f.radio_button  :rating, 4 %> <%= f.label :rating_4, "4" %>
<%= f.radio_button  :rating, 5 %> <%= f.label :rating_5, "5" %>

Теперь давайте внимательно посмотрим на этот код. Сначала мы даем ярлыку оценки, чтобы сообщить пользователю, для чего нужны радиокнопки, затем мы перемещаемся по фактическим кнопкам. Первый параметр для метода radio_button - это атрибут модели, с которым мы работаем, а второй - значение для отправки сервера при отправке. После каждой кнопки у нас есть метка, чтобы сообщить пользователю, какой рейтинг соответствует этой кнопке, причина, по которой мы проходим: rating_ #, потому что, когда rails генерирует радиокнопку, она дает идентификатор атрибута_value, поэтому наши метки привязываются к этим значениям. Вот как выглядит новая форма с помощью переключателей, обратите внимание, что при редактировании фильма Rails автоматически выбирает переключатель, соответствующий предыдущему рейтингу из базы данных.

На этом заканчивается первая часть. В предыдущем разделе мы получили приложение для оценки фильмов с земли, используя мощь генераторов Rails и некоторый базовый код представления. В следующем разделе мы сделаем наше приложение несколько более привлекательным, добавив некоторые графики и CSS-код для создания представлений.

Styling

Макеты

Сначала мы рассмотрим макеты. Не вдаваясь в слишком подробные макеты, удерживайте элементы на странице, которая не изменяется в приложении. Например, заголовок, нижний колонтитул и навигация обычно (и по праву) остаются неизменными на веб-сайте. Несмотря на то, что наше приложение довольно тривиально, макет имеет важное значение для согласованности.

Наша цель - включить логотип, фоновое изображение и центрированный контейнер для контента на каждой странице. Сначала нам нужно создать нашу страницу с широким расположением приложений. Rails достаточно любезны, чтобы создать файл макета большой модели, но это не будет применяться к пользовательским страницам, когда мы перейдем к этой части, поэтому нам нужно изменить ее на глобальный макет. Это легко сделать, переименовывая макеты app viewss movies.html.erb в app views layouts application.html.erb. Теперь нам нужно открыть файл и внести несколько изменений. Сначала давайте обернем весь наш контент в div, называемом pagewrap. Это хорошо, потому что это дает нам немного больше контроля в CSS, чем мы обычно получаем только с телом. Это можно сделать, просто включив отверстие чуть ниже тела и закрыв его прямо над телом.

# app/views/layouts/application.html.erb
...
<body>
  <div id="pagewrap">
    ...
  </div>
</body>
...

Пока мы в этом файле, давайте продолжим и добавим файл CSS, который мы создадим дальше. Найдите строку (9 в моем файле), которая говорит stylesheet_link_tag «scaffold», и добавьте в нее запятую и «стиль», чтобы она выглядела так:

# app/views/layouts/application.html.erb
<%= stylesheet_link_tag 'scaffold', 'style' %>

Это вспомогательный метод, предоставляемый рельсами, который создает для нас тег, и ссылки на файл style.css в нашем каталоге stylesheets. В общедоступных таблицах стилей создается файл под названием style.css. Поскольку это не действительно учебник по CSS, я только просмотрю объявления.

# public/stylesheets/style.css
html, body {
  background-image: url(/images/bg_body.jpg);
}
#pagewrap {
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;
  margin: 0 auto;
  padding: 10px;
  width: 900px;
  /* logo */
  background: white url(/images/logo.png) no-repeat;
  padding-top: 72px;
}

Я применяю фоновое изображение к тегу body, так что оно будет охватывать всю страницу. Элемент pagewrap, который мы создали ранее, имеет закругленные углы (только в Safari и Firefox изредка IE), центрированный с использованием поля, некоторые дополнения, чтобы вставлять содержимое, ширину 900 пикселей и неповторяющееся фоновое изображение, которое является нашим логотипом. Содержимое нажимается на 72 пикселя, чтобы разместить логотип, что-то вроде взлома, но просто легкий способ бросить логотип на странице. К сожалению, я не могу распространять фоновое изображение или логотип, потому что они были созданы с использованием частей из шаблона, который я купил на ThemeForest.net. Но не так ли теперь лучше?

Добавление звезд

Страница индекса довольно хромает, потому что она просто перечисляет название фильма и целое число для рейтинга. Давайте добавим некоторую магию CSS, чтобы сделать ее немного более красивой. Сначала давайте обновить приложение, просмотрев фильмы index.html.erb, изменив ячейку таблицы, которая содержит рейтинг, в строке 12. Мы обернем рейтинг в div специальным классом, содержащим количество звезд для показа. Мы также используем метод pluralize helper в Rails, который выводит число, переданное ему, и добавляет слово после номера, делая его множественным, если это необходимо.

# app/views/movies/index.html.erb
<td><div class="star-<%=h movie.rating %> rating"><%=pluralize movie.rating, "Star" %></div></td>

Теперь давайте создадим необходимый CSS-код. Примечание. Я не включил изображение в разметку HTML, так что если пользователь отключил CSS, они не будут видеть никаких звезд только что-то вроде «3 звезды».

# public/stylesheets/style.css
.rating {
  background: url(/images/stars.png) no-repeat;
  height: 26px;
  overflow: hidden;
  text-indent: -1000px;
}
.star-5 { width: 115px; }
.star-4 { width: 92px; }
.star-3 { width: 69px; }
.star-2 { width: 46px; }
.star-1 { width: 23px; }

Мы применяем не повторяющееся фоновое изображение 5 звезд ко всем разделителям рейтинга, а затем изменяем ширину (с шагом 20%), чтобы скрывать звезды. Мы также нажимаем текст «# Stars» на странице с отрицательным текстовым отступом, так как звезды достаточно понятны, чтобы не требовать и фактических слов.

Необязательно: Удаление страницы просмотра

Последнее, что я сделал, это удалить ссылки на страницу показа. Казалось, немного избыточно включать его, поскольку на индексной странице была указана вся соответствующая информация. Вы можете сделать то же самое, открыв app views movies index.html.erb и удалив строку 13, ссылку на страницу показа. Вам также нужно открыть контроллеры приложений movies_controller.rb и обновить строки 48 и 65 направить redirect_to, вместо этого сделайте параметр movies_url.

Плагин restful_authenticatio

Теперь, когда мы сделали это с помощью основ, добавьте пользователей! Цель первой половины этого учебника состояла в том, чтобы имитировать устаревшее приложение, которое вы уже создали. Поэтому с этого момента вы можете легко применить то, что мы узнаем, к любому приложению, которое вы создаете. Самое замечательное в плагине restful_authentication заключается в том, что он абстрагирует логику аутентификации от других моделей и делает ее довольно быстрой и безболезненной для реализации.

Установить restful_authenticatio

Прежде всего нам нужно установить плагин restful_authentication, остановить сервер, нажав CTRL + C, если вы его запустили. На странице GitHub для restful_authentication есть инструкции по установке, но вот версия дайджеста читателя:

script/plugin install http://github.com/technoweenie/restful-authentication.git restful_authenticatio

Передача во второй restful_authentication указывает на рельсы, которые мы хотим переименовать в папку плагина, а не restful-authenticatoin. Обоснование объясняется в заголовке «Установка» для тех, кто заинтересован. Хорошо, теперь эти команды в основном уходят на сервер и извлекают все файлы restful_authentication и копируют их на ваш сервер. Он также создает сценарий генератора, который мы можем запускать для создания необходимых контроллеров, моделей и представлений в нашей папке приложения.

script/generate authenticated user sessions --include-activatio

Используя аутентифицированный генератор, мы говорим, что хотим назвать модель, которая обрабатывает пользователя пользовательской информации, и модель, которая обрабатывает сеансы, называемые сеансами, достаточно легко? Но почему мы отделяем их? Если вы действительно думаете о том, что регистрация пользователя и получение их информации аналогичны их аутентификации, но на самом деле это тоже очень отличается. Один из них хранит долгосрочную регистрационную информацию для пользователя, а другой более временный и стирается после выхода из системы. Поэтому на самом деле имеет смысл разделить их на наш дизайн. Мы также передаем флаг включения включения, чтобы он генерировал необходимые почтовые программы для активации учетных записей пользователей по электронной почте.

Хорошо, что теперь у нас есть файлы в папке приложения, но мы не совсем сделали это в терминале. Генератор выше также создал некоторые миграции для нас, которые создают таблицы пользователей и сеансов в нашей базе данных, но теперь нам нужно связать пользователей с их видеозаписями. Давайте используем генератор миграции, чтобы добавить столбец user_id в таблицу фильмов.

script/generate migration add_user_id_to_movie user_id:integer

Rails 2.0 принес некоторые действительно отличные автоматизации для генератора миграции. Из-за схемы имен add_user_it_to_movie рельсы предполагают, что мы имеем в виду, и создаем схему, которая делает именно это. Итак, все, что нам нужно сделать, - это запустить

rake db:migrate

и наша база данных обновлена. Если вы хотите увидеть файл миграции, который он создал, чтобы понять, что мы сделали, вы можете проверить миграцию приложения db и найти файл add_user_id_to_movie.rb. Хорошо, мы все закончили на терминале!

Связывание пользователей и фильмов

Чтобы пользователь мог «владеть» фильмом, мы должны сообщить рельсам, что они делают. Это происходит через ассоциации, объявленные в моделях. Сначала давайте обновим модель пользователя, созданную нашим генератором, моделью приложений user.rb. Обычно я добавляю следующий код прямо над первым объявлением метода, активируя в этом случае.

#app/models/user.rb
has_many  :movies

Это довольно прямолинейно, мы рассказываем о том, что у пользователя есть много записей фильмов, связанных с их учетной записью. Теперь давайте сообщим модель фильма ассоциированного в моделях app movie.rb. Добавьте этот код прямо под нашими методами проверки ранее.

#app/models/movie.rb
belongs_to  :user

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

Маршруты

Это скорее изменение пользовательского опыта, но что-то должно включать все приложения. В настоящее время, если пользователь хочет зарегистрировать URL-адрес, пользователи example.com являются новыми или если они хотят входить в систему, то это example.com-сессии новые, немного подробные на мой взгляд. Таким образом, мы добавим несколько настраиваемых маршрутов в config routes.rb, мой включил строку 8.

# config/routes.rb
map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate'
map.signup '/signup', :controller => 'users', :action => 'new'
map.login '/login', :controller => 'sessions', :action => 'new'
map.logout '/logout', :controller => 'sessions', :action => 'destroy'

Как вы можете видеть здесь, мы объявляем активный, регистрационный номер, логин и выход из системы для своих очевидных партнеров. Это сделает наши URL более разумными и легко запоминаемыми. Обратите внимание, что для активации требуется строка, в которой будет указан код активации, который мы отправляем по электронной почте пользователям для проверки адресов электронной почты.

Проверка адресов электронной почты

Общепринятой практикой является то, что на многих веб-сайтах требуется, чтобы пользователи проверяли адреса электронной почты, щелкая ссылку в электронном письме, отправленном по адресу, который они предоставляют. В других языках и структурах это несколько сложно, но плагины restful_authentication и рельсовые почтовые программы делают эту расширенную функциональность очень простой. Однако, прежде чем мы сможем отправить электронные письма, нам нужно указать рельсы, как аутентифицироваться с нашим SMTP-сервером. Теперь это зависит от хоста и хоста, и вам нужно будет связаться с вашим хостом, чтобы определить, как заполнить эти параметры. Примечание. Сначала вам нужно сначала создать инициализаторы файлов mail.rb.

# config/initializers/mail.rb
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
    :address => "mail.example-domain.com",
    :port => 25,
    :domain => "www.example-domain.com",
    :authentication => :login,
    :user_name => "user@example-domain.com",
    :password => "secret"
}

Пока мы устанавливаем значения по умолчанию, мы должны определить URL-адрес нашего веб-сайта, который мы будем использовать во всех наших электронных письмах. Вы можете задаться вопросом, почему мы это сделаем, и причина в том, что наше приложение будет доказано в будущем. Например, пока мы разрабатываем локально, домен является localhost: 3000, и, предположительно, наш производственный домен отличается. Если в какой-то момент в будущем будет изменен производственный URL-адрес, мы можем обновить его в одном месте и не беспокоиться о других отсутствующих других изменениях. Но где мы размещаем эти значения по умолчанию? Rails создал некоторые файлы конфигурации, которые загружаются в зависимости от среды, в которой мы находимся: разработка, тестирование или производство. Начиная с разработки, мы должны изменить конфигурационные среды development.rb в строке 19.

# config/environments/development.rb
SITE_URL  = "localhost:3000"

А также в конфигурационных средах production.rb по строке 30.

# config/environments/production.rb
SITE_URL  = "noahhendrix.com"

Теперь нам нужно обновить файл модели user_mailer, модели приложений user_mailer.rb, чтобы использовать нашу новую переменную SITE_URL. Эти изменения должны быть сделаны на строках 6, 13 и 20, удалите YOURSITE и замените его на # {SITE_URL}. В строке 19 вам необходимо обновить адрес электронной почты до своего.

Вот как выглядит электронное письмо с просьбой активировать свою учетную запись.

Они также получают электронное письмо после активации учетной записи

Обновление наших контроллеров

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

Мы собираемся обновить кучу строк и потому, что они настолько почти одинаковы, мы не будем перебирать их по отдельности. По сути, мы говорим контроллеру, чтобы ограничивать все находки переменной current_user (т. Е. Добавлять «WHERE user_id = ##» к запросам базы данных). Переменная current_user - это что-то restful_authentication, которое дает нам возможность использовать в нашем контроллере по этой конкретной причине. Я включил приблизительные номера строк, но если они для вас разные, то знайте, что мы только модифицируем методы: индексируем, показываем, редактируем, создаем, обновляем и уничтожаем. Примечание: переменная Movie изменяется на фильмы, потому что мы получаем доступ к ней через пользователя, который появляется, когда мы говорим, что у пользователя много фильмов.

# app/controllers/movies_controller.rb
Line 8: @movies = current_user.movies
Line 20: @movie  = current_user.movies.find(params[:id])
Line 42: @movie  = current_user.movies.find(params[:id])
Line 49: @movie  = current_user.movies.create(params[:movie])
Line 67: @movie  = current_user.movies.find(params[:id])
Line 85: @movie  = current_user.movies.find(params[:id])

Хотя мы открываем этот файл вверху (строка 2), нам нужно добавить фильтр до. Это говорит о том, что до того, как он выполнит какой-либо из приведенных ниже методов, необходимо сначала запустить метод, который мы предоставляем.

# app/controllers/movies_controller.rb
before_filter :login_required

Метод: login_required предоставляется плагином и в основном проверяет, вошел ли пользователь в систему, и если он не перенаправит их на страницу входа в систему.

Хорошо, не так уж плохо, не так ли? У нас есть несколько последних вещей для очистки до того, как плагин полностью функционирует. В контроллерах приложений session_controller.rb и контроллерах приложений users_controller.rb есть оператор include, который необходимо удалить и добавить в контроллеры приложений application_controller.rb. Эта строка включает в себя необходимые файлы задней панели, которые плагин использует для управления пользователями и сеансами. Я поставил шахту в строке 5.

# app/controllers/application_controller.rb
include AuthenticatedSystem

Если вам интересно, откуда он извлекает этот файл, вы можете найти его в lib authenticated_system.rb.

Добавление списания пароля

Обновление контроллера пользователей

Нам нужно добавить два метода к контроллеру пользователей, контроллерам приложений users_controllers.rb, которые позаботятся о том, чтобы пользователи могли сбросить свой пароль. Однако, прежде чем мы погрузимся в код, давайте займем секунду, чтобы обсудить наш план. Мы хотим разрешить пользователю щелкнуть ссылку, в которой говорится, что они забыли свой пароль. Затем они будут отправлены на страницу с вопросом, какой адрес электронной почты они использовали при создании своей учетной записи, после того как они отправят, что мы запустим электронное письмо со ссылкой, содержащей специальный хэш, который они смогут щелкнуть. Как только они откроют ссылку в своем электронном письме, у них будет форма для выбора пароля и подтверждения.

Хорошо, давайте посмотрим на каждую функцию отдельно, начиная с забытого.

# app/controllers/users_controller.rb
def forgot
  if request.post?
    user = User.find_by_email(params[:user][:email])
    respond_to do |format|
      if user
        user.create_reset_code
        flash[:notice] = "Reset code sent to #{user.email}"
        format.html { redirect_to login_path }
        format.xml { render :xml => user.email, :status => :created }
      else
        flash[:error] = "#{params[:user][:email]} does not exist in system"
        format.html { redirect_to login_path }
        format.xml { render :xml => user.email, :status => :unprocessable_entity }
      end
    end
  end
end

Вот действие со ссылкой на форму, в которой они вводят свой адрес электронной почты. Сначала мы проверяем, отправили ли они форму через почтовый запрос, если мы ничего не делаем, потому что мы ждем отправки формы. После того, как мы разместим данные, мы найдем информацию пользователей, используя предоставленный адрес электронной почты, чтобы убедиться, что они существуют. Мы используем блок формата response_to, чтобы мы могли отвечать на запросы xml и html. В этом уроке мы не будем использовать формат XML, но хорошо его предоставить для веб-сервисов. Теперь вы увидите, что у нас есть простой оператор if, говорящий, что если пользователь не является nil (подразумевается), мы хотим запустить метод create_reset_code и уведомить пользователя с помощью метода flash, чтобы проверить их электронную почту для ссылки на сброс. Если пользователь не существует, мы также сообщаем об этом.

Теперь давайте посмотрим на действие сброса, которое они видят после того, как они нажмут на ссылку в своем письме.

# app/controllers/users_controller.rb
def reset
  @user = User.find_by_reset_code(params[:reset_code]) unless params[:reset_code].nil?
  if request.post?
    if @user.update_attributes(:password => params[:user][:password], :password_confirmation => params[:user][:password_confirmation])
      self.current_user = @user
      @user.delete_reset_code
      flash[:notice] = "Password reset successfully for #{@user.email}"
      redirect_to root_url
    else
      render :action => :reset
    end
  end
end

Сначала мы находим информацию пользователей через код сброса, чтобы убедиться, что они существуют в базе данных. Если есть данные пользователя, мы регистрируем их и представляем форму для сброса пароля. Затем мы проверяем, просто ли они загружают форму или уже отправили ее. Если есть данные, мы обновляем пароль до того, который они поставили. Мы устанавливаем current_user этому пользователю и удаляем код сброса, чтобы никто другой не мог использовать ссылку для изменения своего пароля. Мы даем им флеш-уведомление, подтверждающее сброс. Если мы не сможем обновить пароль, мы отправим их обратно на страницу с ошибками.

Обновление модели пользователя

Некоторое из этого довольно запутанно, потому что мы не полностью реализовали некоторые методы, которые мы использовали, такие как: create_reset_code, recent_reset?, и delete_reset_code. Мы поместим их в пользовательскую модель, модели приложений user.rb, прямо над словом, защищенным снизу.

#app/models/user.rb
#reset methods
def create_reset_code
  @reset = true
  self.attributes = {:reset_code => Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )}
  save(false)
end
def recently_reset?
  @reset
end
def delete_reset_code
  self.attributes = {:reset_code => nil}
  save(false)
end

В функции create_reset_code мы устанавливаем переменную экземпляра @reset в true, чтобы наше приложение могло помнить, что они недавно сбросили свой пароль. Затем мы устанавливаем reset_code в базе данных (который мы еще добавили столбец для) в хэш текущего времени, чтобы сделать его уникальным. Затем мы сохраняем этот reset_code в базе данных, ложный параметр сообщает rails игнорировать проверки, которые мы можем сделать, потому что мы сами устанавливаем код, а не пользователи.

the recent_reset? метод - это просто, чтобы мы могли проверить, является ли переменная @reset верной или ложной. И, наконец, delete_reset_code делает именно то, что имя имеет имя, удаляет код сброса из базы данных.

Создание просмотров и сброса просмотров

Мы говорили о формах, которые пользователь должен заполнить, чтобы сбросить свой пароль, отпустить голову и создать их. Сначала в приложении каталога отображаются пользователи с именем forget.html.erb.

# app/views/users/forgot.html.erb
<%= error_messages_for :user %>
<% form_for :user do |f| -%>
  <p>
    Reset Password Request
  </p>
  <p>
    <label for="email">Email</label><br />
    <%= f.text_field :email %>
  </p>
  <p>
    <%= link_to "Cancel", login_path %>
    <%= submit_tag 'Submit' %>
  </p>
<% end -%>

Это довольно распространенная форма, где мы просим пользователя отправить электронную почту. Теперь нам нужно создать форму для сброса пароля в том же каталоге, что и выше, создайте файл с именем reset.html.erb.

# app/views/users/reset.html.erb
<%= error_messages_for :user %>
<% form_for :user do |f| -%>
  <p>
    Pick a new password for <span><%= @user.email %></span>
  </p>
  <p>
    <label for="password">Password</label><br />
    <%= f.password_field :password %>
  </p>
  <p>
    <label for="password">Confirm Password</label><br />
    <%= f.password_field :password_confirmation %>
  </p>
  <p>
    <%= submit_tag 'Reset' %>
  </p>
<% end -%>

Отправка электронной почты пользователю Сброс ссылки

Хорошо, теперь, когда у нас есть настройки форм, можно изменить класс почтовой программы пользователя для отправки сбросных ссылок. Так как мы работаем с представлениями, давайте начнем там. Если традиционное представление переводится грубо на веб-страницу, тогда просмотр почты будет переводить на электронную почту. В основном это основной макет электронной почты, который мы хотим отправить пользователю, оставляя пятна для переменных, которые предоставит наш контроллер. Файл, который мы собираемся создать, - это просмотр приложений user_mailer reset_notification.html.erb и вставка этого кода:

# app/views/user_mailer/reset_notification.html.erb
Request to reset password received for <%= @user.login %>
Visit this url to choose a new password:
<%= @url %>
(Your password will remain the same if no action is taken)

Это все довольно распространенная отметка, обратите внимание, что у нас есть место для URL-адреса и имени пользователя. Мы также говорим им, что если они ничего не сделают, пароль не будет изменен. Теперь давайте перейдем в приложения user_mail.rb и создадим метод reset_notification, вот где наше представление получает логин пользователя и сбрасывает URL-адреса. Вставьте этот код где-нибудь после активации, но выше защищенного.

# app/models/user_mailer.rb
...
def reset_notification(user)
  setup_email(user)
  @subject    += 'Link to reset your password'
  @body[:url]  = "#{SITE_URL}/reset/#{user.reset_code}"
end
...

Здесь мы делаем несколько вещей. Сначала мы вызываем метод setup_email, который объявляется под защищенным (защищенный означает, что только этот класс может вызывать этот метод), что является некоторыми родовыми настройками электронной почты. Мы добавляем строку к теме, чтобы помочь пользователю определить цель электронной почты от объекта. Затем мы установили этот URL, о котором мы говорили ранее, мы используем переменную # {SITE_URL}, которую мы установили ранее. Переменная reset_code исходит из пользовательской модели, которую мы установили ранее, используя метод create_reset_code, помните это?

Еще одна модель, которую мы должны обновить, модели приложений user_observer.rb. В основном, это то, где мы говорим, чтобы отправить это письмо, если переменная @reset верна. Эти методы выполняются всякий раз, когда пользователь взаимодействует, в этом случае после того, как мы сохраним его в базе данных, мы хотим проверить, нужно ли им получать сброс электронной почты. После того, как строка, которая отправляет сообщение активации, добавляет этот код.

# app/models/user_observer.rb
...
UserMailer.deliver_reset_notification(user) if user.recently_reset?
...

Хорошо, чтобы обновить еще один файл, прежде чем мы перейдем в терминал, чтобы добавить столбец reset_code. Помните, что URL-адрес пользователя отправлен по электронной почте? Ну, мы должны установить это в файле маршрутов, config routes.rb. На строке ниже, где мы настраиваем маршрут выхода, добавьте следующие две строки:

# config/routes.rb
map.forgot    '/forgot', :controller => 'users', :action => 'forgot'
map.reset     'reset/:reset_code', :controller => 'users', :action => 'reset'

Это похоже на приведенные выше маршруты, мы сопоставляем дружественные URL-адреса с соответствующими контроллерами и действиями. Хорошо, давайте переместимся в терминал. Итак, теперь мы будем использовать тот же самый генератор миграции, который мы использовали для добавления user_id в таблицу фильмов. Таким образом, этот код будет выглядеть очень знакомым.

script/generate migration add_reset_code_to_user reset_code:string

Не забудьте запустить

rake db:migrate

для обновления базы данных.

Очистка свободных концов

Установка основной корневой страницы

Сначала нам нужно удалить файл public.html. Это страница и переопределит установленный по умолчанию контроллер. Затем откройте config routes.rb и раскомментируйте строку 46 (один запустив map.root). Измените приглашение в фильм, это говорит о том, что рельсы отображают контроллер фильма как наш по умолчанию, если кто-то перебирается на localhost: 3000 или корень нашего производственного домена.

Добавление ссылок, сброса и выхода из системы

Хорошо, теперь мы переходим к просмотрам. в сеансах app views new.html.erb мы должны удалить строки 8 и 11, чтобы позволить нашим пользователям запоминать их сеанс, чтобы они не переписывались каждый раз, когда они посещают. В строке 11 есть абзац абзаца, нам нужно добавить ссылку и забыть пароли ссылок внутри этого элемента.

# app/views/sessions/new.html/erb
<%= link_to 'Sign Up', :signup %>
<%= link_to 'Forgot Password?', :forgot %>

Теперь пользователи могут легко зарегистрироваться, войти в систему или сбросить свой пароль, но нам нужно включить ссылку для выхода из системы, как только они войдут в систему, чтобы они могли завершить свой сеанс. Мы сделаем это в файле макета приложения, app views layouts application.html.erb, чтобы он отображался на всех страницах. Я добавил мой прямо над флеш-сообщениями, но ниже div.

# app/views/layouts/application.html.erb
<div class="user">
  <%= link_to "Logout", :logout unless !logged_in? %>
</div>

Обратите внимание, что мы говорим, чтобы включить ссылку, если logged_in? false, logged_in? является помощником, который предоставляет плагин, который возвращает true, если пользователь вошел в систему и false, если он отсутствует, и, конечно, мы хотим только ссылку, если они действительно вошли в систему.

Пока мы здесь, добавим еще один тип флэш-сообщения, предупреждение. Это должно отображать ошибки для пользователя, переданного с контроллеров. Под существующим добавьте эту строку.

# app/views/layouts/application.html.erb
<p style="color: red"><%= flash[:alert] %></p>

Предотвращение автоматического входа в систему при регистрации

Возможно, вы заметили, что при регистрации журналов приложений вы без предварительной проверки подлинности электронной почты, хотя это предотвращает любые последующие логины. Это что-то включено в пользовательский контроллер по умолчанию, где, если пользователь проходит проверку, они регистрируются путем установки current_user только что созданной модели пользователя. В нашем приложении это ошибка, потому что мы хотим, чтобы пользователь сначала аутентифицировал свой адрес электронной почты. Мы можем исправить это поведение в контроллерах приложений users_controller.rb по строке 16, нам нужно удалить или закомментировать, где он устанавливает current_user = @user.

Также в качестве полезного намека на пользователей мы должны изменить строку 17, где он сообщает пользователю, что они успешно подписались на то, что дает им указание проверить их электронную почту.

# app/controllers/users_controller.rb
flash[:notice] = "Thanks for signing up! Please check your email to activate your account."

Хорошо, это все, что нам нужно сделать для нашей базовой аутентификации пользователей. Надеюсь, это помогло пошаговое руководство по установке и использованию restful_authentication в вашем приложении rails. Я знаю, что это очень упрощенно, поэтому отправляйте любые пожелания в комментариях или свяжитесь со мной в twitter (@noahhendrix), и я постараюсь обратиться к ним. Спасибо за прочтение!

Следуйте за нами в Твиттере или подписаться на RSS-канал NETTUTS для более ежедневных веб-разработок и статей.