りゅうじの学習blog

学習したことをアウトプットしていきます。

Sorceryでログイン機能を実装する

こんにちは。りゅうじです。

sorcery を使うのでまずはインストールします。

インストール

#Gemfile

gem 'sorcery'
#ターミナル

$ bundle install --path vendor/bundle

初期設定

#ターミナル

$ bundle exec rails g sorcery:install

このコマンドで必要最低限のファイルが生成される。

DBに反映

#db/migrate/20xxxxxxx_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 :first_name, null: false
       t.string :last_name, null:false
 
       t.timestamps                null: false
     end
 
     add_index :users, :email, unique: true
   end
 end

初期設定のコマンドでこんなマイグレーションファイルが生成されていて

認証に必要最低限のカラムが定義されています。(今回は名前を追記しています)

このように他にもカラムが欲しい場合は自分で追記しましょう。

#ターミナル

$ bundle exec rails db:migrate

モデルにバリデーションを設定

#app/model/user.rb

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

if: -> { new_record? || changes[:crypted_password] }

登録したユーザーがパスワード以外を更新したい場合にパスワードの入力を省略させます。

登録済みなのに名前を更新しようとしたら毎回パスワード書くことになるの嫌ですよね。

routesの設定

#config/routes.rb

root 'static_pages#top'
 
   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

コントローラーの設定

#app/controllers/user_sessions_controller.rb

class UserSessionsController < ApplicationController

  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
#app/controllers/users_controller.rb

class UsersController < ApplicationController
   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(:email, :password, :password_confirmation, :last_name, :first_name)
   end
 end

user_sessions_controller ⇨ログイン

users_controller ⇨新規登録

ビューの設定

#app/views/user_sessions/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 url: login_path, local: true do |f| %>
         <div class="form-group">
           <%= f.label :email %>
           <%= f.text_field :email, class: 'form-control' %>
         </div>
         <div class="form-group">
           <%= f.label :password %>
           <%= f.password_field :password, class: 'form-control' %>
         </div>
         <div class="actions">
           <%= f.submit 'ログイン', class: 'btn btn-primary' %>
         </div>
       <% end %>
       <div class='text-center'>
         <%= link_to '登録ページへ', new_user_path %>
         <a href="#">パスワードをお忘れの方はこちら</a>
       </div>
     </div>
   </div>
 </div>
#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 |f| %>
         <div class="form-group">
           <%= f.label :last_name %>
           <%= f.text_field :last_name, class: 'form-control' %>
         </div>
         <div class="form-group">
           <%= f.label :first_name %>
           <%= f.text_field :first_name, class: 'form-control' %>
         </div>
         <div class="form-group">
           <%= f.label :email %>
           <%= f.email_field :email, class: 'form-control' %>
         </div>
         <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>
         <%= f.submit '登録', class: 'btn btn-primary' %>
       <% end %>
       <div class='text-center'>
         <%= link_to 'ログインページへ', login_path %>
       </div>
     </div>
   </div>
 </div>

user_sessions にはモデルがない

users モデルがある

この違いからform_with の後の記述が異なります。

基本的に model: を使うと覚えておいて

今回のログインに使うuser_sessions のような場合は url: になります。

またi18n での日本語訳の場合、model: ならば自動で翻訳してくれます。url: の場合は自分でlavel に追記する必要がある事を覚えておいて下さい。

i18n がわからない方はこちらの過去記事をどうぞ。

https://ryujisurf55.hatenablog.com/entry/2021/04/24/211738

sorcery で使えるようになるメソッドがあるので、Coreのものだけを次回の記事にしてみます。

最後に

読んでいただいた方、ありがとうございました。