sorceryを使ってログイン機能を実装する
sorceryとは
Railsに認証機能を実装するためのライブラリです。
認証機能とは、システムへのログインやユーザの有効性確認を行うための機能のことを言います。
同じように認証機能を提供してくれているものとしてdeviseなどがあります。
sorceryの使い方
まずgemfileに以下を追加して、$bundle installを行います。
gem 'sorcery', '0.14.0'
以下のコマンドでsorceryに必須のカラムやモデルを追加。
$ rails g sorcery:install $ rails db:migrate
このコマンドで通常で言うところの、$ rails g model の時のようにmodelとかカラムを作ってくれます。
config/initializers/sorcery.rb
models/users.rb
db/migrate/00000_sorcery_core.rb
が生成されます。
scafford_controllerを使って、userコントローラとビューファイルを作ります。
$ rails generate scafford_controller user email:string crypted_password:string salt:string
app/controller/users_controller.rb
app/views/users
が生成されます。ここで生成された要らないビューファイルを消去します。
Userモデルにlast_nameとfirst_nameのカラムを追加します。
ここで生成されたマイグレーションファイルに、null制約をつけます。null: false
$ rails generate migration AddNameToUsers last_name:string first_name:string $ rails db:migrate
Userコントローラのuser_paramsのコードを書き換えます。
:crypted_passwordと:saltが書いてありますが、:password, :password_confirmationに書き換えます。
新規登録画面でformから送られてくる値をpermitに書きます。
def user_params params.require(:user).permit(:email, :password, :password_confirmation, :last_name, :first_name) end
※ここでコントローラの不要なコードも削除して、スッキリさせました。
ビューファイルにもcrypted_passwordとsaltが書いてあるので、passwordとpassword_confirmationに書き換えます。
Userモデルのバリデーションを追加します。
class User < ApplicationRecord authenticates_with_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 validates :last_name, presence: true, length: { maximum: 255 } validates :first_name, presence: true, length: { maximum: 255 } end
ここで使われてるコードの難しいところを下記でまとめてみました。
sorceryが準備しているメソッド。
Userモデルで必要なクラスメソッドとインスタンスメソッドを得ることができます。
authenticates_with_sorcery!
登録したユーザーがパスワード以外のプロフィール項目を更新したいときに、
パスワードの入力を省略できるようになります。
if: -> { new_record? || changes[:crypted_password] }
ログイン機能を作るために、新しいコントローラを作成します。
$ rails generate controller UserSessions new create destroy
生成されたSessionsコントローラを下記のように書きます。
class UserSessionsController < ApplicationController def new; end def create @user = login(params[:email], params[:password]) if @user redirect_back_or_to root_path, notice: 'Login successful' else flash.now[:alert] = 'Login failed' render :new end end def destroy logout redirect_to root_path, notice: 'Logged out!' end end
redirect_back_or_toメソッドはSorceryが提供しているメソッドです。
SorceryがURLを保存している場合は、
コードで指定したURLではなく保存されたURLにリダイレクトします。
これで便利なのは、あるページにアクセスしたユーザをまずログインさせたいという場合に、
Sorceryがそのユーザをログインページに誘導し、
ログインが成功したら最初に訪れようとしていたページに戻してくれる点です。
今回のコードでは、root_pathが指定したURLになります。
ユーザーの新規登録画面を作成します。
<%= form_with model: @user, local: true do |f| %>
ログイン画面を作成します。
<%= form_with url: login_path, local: true do |f| %>
ルーティングを変更します。
get 'login', to: 'user_sessions#new', as: :login post 'login', to: 'user_sessions#create' delete 'logout', to: 'user_sessions#destroy', as: :logout resources :users, only: %i[new create]
sorceryで使えるようになるメソッド
require_login
logout
logged_in?
current_user
redirect_back_or_to
not_authenticated
などなど....