はじめに
前回に引き続いての投稿です!
今回は、ログイン機能の実装についてまとめます!!
目次
Userモデルを作成
まずUserモデルを作成します。
rails g model User name:string email:string password_digest: string
こちらを実行し、rails db:migrateしてください。
password_digestというのは、Rails標準機能のhas_secure_passwordを使用する際の命名規則となります。
gemを導入
先程作成したpassword_digestには、入力されたパスワードを不可逆にハッシュ化したものが入ります。passwordをそのままDBに保存すると、流出した際に大変危険ですので、このようにすることで漏洩対策となります。
そこで、ハッシュ関数を提供する「bcrypt」というgemを導入します。
gem 'bcrypt', '~> 3.1.7'
gemfileに追記したら、bundle installします。
user.rbに追記
gem導入後、やることは一つだけ。以下を追記します。
has_secure_password
これでした準備が完了です!次に、controllerを実装していきます。
ログイン機能実装
ログイン機能は、session[:user_id]というセッションにユーザーのidを保持することで、実現します。
まず、sessions_controller.rbを、ログイン用のnewメソッドと共に作成します。
rails g controller Sessions new
このnewアクションがログイン画面への遷移となります。今回は、以下のようなフォームにしました。
h1 ログイン
= form_with scope: :session, local: true do |f|
.form-group
= f.label :email, 'メールアドレス'
= f.text_field :email, class: 'form-control', id: 'session_email'
.form-group
= f.label :password, 'パスワード'
= f.password_field :password, class: 'form-control', id: 'session_password'
= f.submit 'ログインする', class: 'btn btn-primary'
送られてくるパラメータをもとに、ログイン処理を行います。
まずは、routesの編集です。
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create' //こちらを追加
def create
// users テーブルから、一致するメールアドレスが存在するか検索します。
user = User.find_by(email: session_params[:email])
// メールアドレスが存在した場合は、パスワードの認証をauthenticateメソッドで行います。
if user&.authenticate(session_params[:password])
// 認証に成功したら、sessionにuserのidを保持します。
session[:user_id] = user.id
redirect_to root_url, notice: 'ログインしました。'
else
render :new
end
end
private
def session_params
params.require(:session).permit(:email, :password)
end
ログイン情報を取得
以下のコードで、ユーザの情報を取得できます。
User.find_by(id: session[:user_id])
しかし、毎回この記述をするのは面倒なので、application.rbにcurrent_userという変数を定義し、どのcontrollerからでも利用できるようにします。また、helper_methodを指定し、viewでも使えるように書きます!
helper_method :current_user
private
def current_user
// session[:user_id]に値があれば(ログインしていれば)、@current_userにログインユーザーの情報を格納する
@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
end
ログアウト機能実装
ログアウト機能は、session[:user_id]を削除することで実現します。
delete 'logout', to: 'session#destroy'
def destroy
reset_session
redirect_to root_url, notice: 'ログアウトしました'
end
viewは以下のようになります
- if current_user
li.nav-item= link_to 'ログアウト', logout_path, method: :delete, class: 'nav-link'
- else
li.nav-item= link_to 'ログイン', login_path, class: 'nav-link'
ログインしてない場合の処理
ログインしなければすべての機能を使えなくする場合は、application_controllerにメソッドを追加します。
before_action :login_required
private
def login_required
// current_userがnil(ログインしていない)とき、ログイン画面にredirectさせる
redirect_to login_url unless current_user
end
上記の記述の場合、ログイン画面もログインしないと見られないというカオスな状況になります。
そこで、session_controllerだけはこの制約を解除します。
skip_before_action :login_required