sorceryを使ったユーザー機能の作成(登録機能編)

・そもそもsorceryとは?

ユーザ認証機能を簡単に実装できるライブラリ、MITライセンスのオープンソースソフトウェアとして公開されている  

パスワード認証機能の他にも、  

・Remember Me  

・Reset Password  etc...

などの色々な機能が揃っていて選んで使うことができる。  

・sorceryの導入  

Gemfileにsorceryを追加して、bundle install  

gem 'sorcery'

Soceryが提供するジェネレータ bundle exec rails g sorcery:installを実行すると、Userモデル、データベースのmigrationを生成される。  

この時生成されるファイルは以下の通り、  

app/models/user.rb  

config/initializers/sorcery.rb  

db/migrate/yyyymmddhhmmss_sorcery_core.rb  

bundle exec rails db:migrateでデータベースにusersテーブルを作成  

app/models/user.rbに  

# app/models/user.rb
class User < ActiveRecord::Base
  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
end

とバリデーションを記述、ここでauthenticates_with_sorcery!

でUserモデルに認証にはSorceryを使用することを伝えている  

if: -> { new_record? || changes[:crypted_password] }は登録したユーザーがパスワード以外のプロフィール項目(属性)を更新したいとき、パスワードの入力を省略するということ   validates :password, confirmation: trueで、passwordというDBに存在しない仮想的な属性(virtual attributes)が追加される。
これに加え今回はUserモデルにlast_name、first_nameカラムを追加して、必須項目であることのバリデーションを追加するのでnull false制約を付与する、既存のdb/migrate/yyyymmddhhmmss_sorcery_core.rbに  

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.string :last_name, null: false
t.string :first_name, null :false

 t.timestamps null: false
end

 add_index :users, :email, unique: true
end
end

と記述、bundle exec rails db:migrate によってカラムの追加が完了  

次に bundle exec rails g controller users new createを実行してapp/controllers/users_controller.rbを作成   コードは以下のように記述  

class UsersController < ApplicationController
   skip_before_action :require_login, only: %i[new create]

   def new
     @user = User.new
   end

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to login_path
    else
      render 'new'
    end
  end

  private

  def user_params
     params.require(:user).permit(:last_name, :first_name, :email, :password, 
:password_confirmation)
  end
end

この時、skip_before_actionメソッドのonlyオプションに指定するアクションを%iの配列で記述
ルーティングはroutes.rbにresousesを使って実装

resources :users, only: %i[new create]

そしてユーザー登録に必要なフォームのテンプレートをに記述

#app/views/users/new.html.erb
<div class="container">
  <div class="row">
    <div class="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
      <h1>ユーザー登録</h1>
      <%= form_with(model:@user,local: true,) do |form| %>
        <div class="form-group">
          <%= form.label :last_name %>
          <%= form.text_field :last_name,class: "form-control" %>
        </div>

        <div class="form-group">
          <%= form.label :first_name %>
          <%= form.text_field :first_name,class: "form-control" %>
        </div>

        <div class="form-group">
          <%= form.label :email %>
          <%= form.text_field :email,class: "form-control" %>
        </div>

        <div class="form-group">
          <%= form.label :password %>
          <%= form.password_field :password,class: "form-control" %>
        </div>

        <div class="form-group">
          <%= form.label :password_confirmation %>
          <%= form.password_field :password_confirmation,class: "form-control" %>
        </div>

        <%= form.submit "登録", class: "btn btn-primary" %>
      <% end %>
      <div class='text-center'>
        <%= link_to 'ログインページへ',login_path %>
      </div>
    </div>
  </div>
</div>

resources :usersとすることでform_withの引数にUserモデルのインスタンスを渡すだけで、railsがモデル名やemailなどの必要なものを取り出して処理してくれている。classオプションでclassを指定できる。
最後に今回フォーム情報の姓名が最大255文字emailが未入力で新規登録ができないようにするバリデーションの追加

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, presence: true, uniqueness: true
  validates :last_name, presence: true, length: { maximum: 255 }
  validates :first_name, presence: true, length: { maximum: 255 }
end

これでSorceryを使った登録機能の完成!!

参考文献

Simple Password Authentication · Sorcery/sorcery Wiki · GitHub

Railsドキュメント

Action View フォームヘルパー - Railsガイド