イメージ図
イメージとしては下記のような設計で作っていくのが基本となるでしょう。実際はdeviseというGemを使うことが多いとは思いますが、基本は同じです。
bcryptとは?
Railsにおいてパスワードを暗号化するために使用するGemになります。なお、Railsをインストールした際にGemfileにはデフォルトでコメントアウトして入っています。
Gemのインストール
Gemfileに下記のようにbcryptというgemがコメントアウトされて入っているのでコメントを削除します。
1 |
# gem 'bcrypt', '~> 3.1.7' ★コメントを削除する。 |
bundleします。
1 |
bundle |
ユーザーテーブルの作成
下記コマンドを実行してユーザーテーブルを作成します。
1 |
rails g model user name:string password_digest:string |
password_digest:string
Railsで用意されているhas_secure_passwordメソッドの機能で使用できるもので、暗号化したパスワードを保存しておくカラムでこの名前は固定になります。
has_secure_passwordメソッド
Railsのモデル内にこのメソッド定義しておくことで「password_digest」と言うカラムを用意しておけばそこに自動できにパスワードを保存して暗号化することができます。
セッションコントローラの作成
Railsではログインをすることはイコール「セッションを張ること」と捉えるのでSessionControllerというコントローラーが作成される場合が多いです。(なお、ここでいうセッションは、Web開発でよく使われるサーバで情報をメモリで保管するセッションのことではなく、リソースとしてのセッションで「Webアプリケーションとのやり取り」というのが正しい意味のようです。)
ログインログアウト時の処理(セッション情報の作成や削除等)を行うセッションコントローラを作成します。
1 |
rails g controller sessions create destroy --skip-template-engine |
--skip-template-engineオプション
セッションコントローラはあくまでセッションの作成や削除を行うためこのオプションを指定してviewファイルを作成しないようにします。
ホームコントローラの作成
ログインのトップページであるホームコントローラを作成します。
1 |
rails g controller home index |
ユーザーコントローラの作成
ユーザー登録機能であるユーザーコントローラを作成します。
1 |
rails g controller users new create me |
ユーザーモデルにhas_secure_passwordを設定
1 2 3 |
class User < ApplicationRecord has_secure_password ★記述 end |
has_secure_passwordを記述することでUserモデルにpassword属性とpassword_confirmation属性が追加されます。これはユーザー登録フォームでよくある「パスワード」と「確認用パスワード」を入力してもらい二つのパスワードが一致していることを要求する物です。(モデルにバリデーションが自動で追加されます。)saveメソッドを呼び出せば「password_digest」というカラムに暗号化されたパスワードが保存される動作になります。
なお、実際にDBに保存されるのは暗号化されたパスワード(password_digest)だけで、passwordやpassword_confirmation等のカラムは実際のDBには存在しません。
has_secure_passwordでできること一覧
- passwordを自動で暗号化する。
- password_confirmation属性が自動で追加され、一致確認のバリデーションを自動で設定します。
- authenticationメソッドで認証チェックをできます。
- 最大文字数が72文字のバリデーションが追加される。
- 「User.create」コマンドでパスワード入力必須バリデーションを追加してくれる。(User.updateは追加されないので注意)
ユーザー登録機能
ユーザーコントローラに下記のようなアクションを実装します。saveメソッドを実行すれば自動的に暗号化パスワードが保存されます。
1 2 3 4 5 6 7 8 9 10 11 12 |
def create user = User.new(user_params) if user.save session[:user_id] = user.id redirect_to 登録成功後のページ else redirect_to 登録失敗後のページ, flash: { user: user, error_messages: user.errors.full_messages } end end |
ログイン時はまず認証を行いセッションにログイン中のユーザーIDを格納するのが普通です。
1 |
session[:user_id] = ユーザーID |
認証機能
セッションコントローラに下記のようなメソッドを追加します。ユーザーモデルのauthenticateメソッドによりユーザー名とパスワードが合っているか検証することが可能です。(これも、has_secure_passwordメソッドをモデルに実装することで、ユーザーモデルに自動で組み込まれるメソッドになります。)
1 2 3 4 5 6 7 8 9 |
def create user = User.find_by(name: params[:session][:name]) if user && user.authenticate(params[:session][:password]) session[:user_id] = user.id redirect_to ログイン成功後のページ else render ログイン失敗後のページ end end |
ApplicationControllerの設定
全てのコントローラに共通するコントローラの設定になります。
1 2 3 4 5 6 7 8 9 10 11 |
class ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :current_user private def current_user return unless session[:user_id] @current_user = User.find_by(id: session[:user_id]) end end |
動作としては、ログインしているユーザーがいれば(セッションにデータが入っていれば)インスタンス変数「@current_user」にログインしているユーザーを設定します。もし該当するユーザーがいなければログインしていない物としてnilを返します。
ログイン後にセッション情報を取り出す構文
下記のメソッドを使ってセッションからユーザー情報を取り出します。
1 |
ユーザーオブジェクト.find_by(id: session[user_id]) |
ただ、こうしたセッションから情報を取得する処理はどのビューでも使う共通の処理になりやすいので共通化するのが一般的になっています。よくあるのはApplicationController(どのコントローラにも継承させる共通コントローラ)にcurrent_userというヘルパーメソッド(どのビューからも使えるメソッド)を定義して意識せず使えるようにします。
ログアウト機能
該当ユーザーのログインしている状態をログアウトしている状態に変えます。具体的には、セッションの中に含まれているユーザーIDをnil(何もない)状態にすればOKです。下記のような感じでセッションから情報を消します。
1 |
session.delete(:user_id) |
この記事へのコメントはありません。