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というカラムはありません。

なので、ビュー側でpasswordpassword_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