railsにsoeceryを導入してログイン機能を実装する
はじめに
soeceryを導入してログイン機能を実装する方法について
soeceryの導入方法
gem 'sorcery'
まずはGemfile
に上記のような記載をしてインストールします。
$ bundle install $ rails g sorcery:install
Userモデルやマイグレーションファイルが作成されます。
マイグレーションファイルに、後述するバリデーションでの制約をデータベース側にも設定するため、下記のように記載してマイグレートします。
class SorceryCore < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :email, null: false t.string :crypted_password t.string :salt t.timestamps null: false end add_index :users, :email, unique: true end end
$ rails db:migrate
application_controller.rb
にbeforeアクションを追加します。
class ApplicationController < ActionController::Base before_action :require_login # ログインしているか判断するメソッド。ログインしてない場合はnot_authenticatedメソッドを呼び出す private def not_authenticated redirect_to login_url end end
続いて、Userモデルを動かすコントローラを作成します。
$ rails g controller users new create
ユーザーのパスワードは暗号化されてデータベースに登録されるため、データベースにpassword
というカラムはありません。
なので、ビュー側でpassword
とpassword_confirmation
という仮想のカラムを作ります。
それを取得できるようにコントローラのストロングパラメータにも追加します。
<div class="form-group"> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> </div> <div class="form-group"> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'form-control' %> </div>
class UsersController < ApplicationController skip_before_action :require_login, only: %i[new create] private def user_params params.require(:user).permit(:email, :password, :password_confirmation) end end
一部のアクションにコールバックを使うときは、except
ではなくonly
を使うようにします。
理由は後からアクションを追加したときに、コールバックが適用されてしまうからです。
またonly
の方がコールバックの対象が明確でわかりやすいからです。
続いてモデルにバリデーションの追加と、先程の仮想フィールドで所得した値を暗号化して保存されるようします。
また、下記のように記述することで、ユーザーが1つの属性を更新したい場合に、パスワードの入力を省略できます。
class User < ApplicationRecord authenticates_with_sorcery! # userモデルにsorceryを使用することを宣言 validates :password, length: { minimum: 3 }, if: -> { new_record? || changes[:crypted_password] } validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] } validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] } validates :email, uniqueness: true, presence: true end
続いて、ログイン用のコントローラを作成します。
$ rails g controller UserSessions new create destroy
class UserSessionsController < ApplicationController skip_before_action :require_login, only: %i[new create] def new; end def create @user = login(params[:email], params[:password]) if @user redirect_back_or_to root_path # フレンドリーフォワーディング else render :new end end def destroy logout redirect_to root_path end end
login
, logout
, redirect_back_or_to
はsorceryで用意されているメソッドです。
最後にルーティングの設定をします。
Rails.application.routes.draw do get 'login', to: 'user_sessions#new' post 'login', to: 'user_sessions#create' delete 'logout', to: 'user_sessions#destroy' resources :users, only: %i[new create] end