sorceryを使ってEmail + Passwordログインを実装
Sorceyを用いたログイン機能実装を解説します。
Railsのログイン機能でよく知らているdeviseよりも機能が少なく、簡単に扱えるのでこちらを採用しております。
実装の詳細に関してはSorceryのGitHubのリポジトリのwikiに書かれています。 今回の実装はwikiのSimple Password Authenticationを参考にしていきます。
Gemの導入
以下をGemfileに追加し、bundle install
を実行してください。
gem 'sorcery'
必要ファイルの生成
sorceryにはgenerateコマンドが備わっています。以下のコマンドを実行すると、必要ファイルが生成されます。
bundle exec rails g sorcery:install create config/initializers/sorcery.rb generate model User --skip-migration invoke active_record create app/models/user.rb invoke test_unit create test/models/user_test.rb create test/fixtures/users.yml insert app/models/user.rb insert app/models/user.rb
migrationファイルの作成
先程のコマンドだと、migrationファイルが生成されていません。以下のコマンドを実行し、migrationファイルを作成しましょう。
※何か問われた場合は、すべて「Y」と入力し進めてください。
$ bundle exec rails g model User name:string email:string
生成されたmigrationファイルを以下のように編集してください。編集が終わったら、bundle exec rake db:migrate
を実行し適用させましょう。
class CreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| t.string :name, null: false t.string :email, null: false t.string :crypted_password t.string :salt t.timestamps null: false end end end
User modelの編集
User modelに対して、sorceryを使用するための設定およびValidationを追加します。app/models/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 end
Routingの設定
ログイン周りのsession管理を扱うControllerをSessionsController
、ユーザーの登録等を行うControllerをUsersController
とし、以下のようにRouting(config/routes.rb
)を編集します。
Rails.application.routes.draw do root to: 'pages#home' get 'login', to: 'sessions#new', as: :login post 'login', to: 'sessions#create' post 'logout', to: 'sessions#destroy', as: :logout resources :users, only: [:new, :create] end
Controllerの作成
Sorceryの実装に関わる、以下の4つのControllerを実装します。
- ApplicationController
- ベースの設定に関する処理
- SessionsController
- セッションの操作に関する処理
- UsersController
- ユーザーの操作に関する処理
- PagesController
- リダイレクト先として仮で用意(こちらは適宜Routingとともに自分で変更して問題ありません)
ApplicationController
ApplicationControllerにSorceryを使用するための設定を記述します。以下のようにapp/controllers/application_controller.rb
を編集してください。
class ApplicationController < ActionController::Base # 全ページでログインを必須とする before_action :require_login private # ログインをしていない場合の処理 def not_authenticated redirect_to login_path, alert: 'ログインしてください。' end end
SessionsController
ログイン・ログアウト周りの処理を行う、SessionsControllerを作成します。以下の内容にてapp/controllers/sessions_controller.rb
を作成してください。
※以下のようにskip_before_action :require_login
を指定することによって、ログインを必須ではなくすることができます。
class SessionsController < ApplicationController skip_before_action :require_login, only: [:new, :create] def new end def create user = login(params[:email], params[:password]) if user.present? redirect_to root_path, notice: 'ログインしました。' else redirect_to login_path, alert: 'ログインに失敗しました。' end end def destroy logout redirect_to login_path, notice: 'ログアウトしました。' end end
UsersController
ユーザー登録を行うためのUsersControllerを作成します。以下の内容にてapp/controllers/users_controller.rb
を作成してください。
class UsersController < ApplicationController skip_before_action :require_login def new @user = User.new end def create @user = User.new(user_params) if @user.save login(params[:user][:email], params[:user][:password]) redirect_to root_path, notice: 'ユーザー登録しました。' else render :new end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end end
PagesController
リダイレクト先の仮ページとしてPagesControllerを用意します。以下の内容にてapp/controllers/pages_controller.rb
を作成してください。
class PagesController < ApplicationController skip_before_action :require_login def home end end
Viewの作成
ここまでで、Routing、Model、Controllerの作成が終わりました。最後に以下のViewファイルを作成します。
※Viewにbootstrap3.xを使用しているため、htmlのclassにはその要素が適用されております。
├── layouts │ └── application.html.erb ├── pages │ └── home.html.erb ├── sessions │ └── new.html.erb └── users └── new.html.erb
pages#home
ログイン・ログアウト及びユーザー登録ページへの導線を配置します。
<div class="container"> <h1>ホーム</h1> <ul> <li><%= link_to 'ログイン', login_path %></li> <li><%= link_to 'ユーザー新規登録', new_user_path %></li> <% if current_user %> <li><%= link_to 'ログアウト', logout_path, method: :post %></li> <% end %> </ul> </div>
sessions#new
ログインページのViewとなります。
<div class="container"> <div class="row"> <div class="col-md-4"></div> <div class="col-md-4"> <%= form_tag login_path, method: :post do %> <div class="form-group"> <label>メールアドレス</label> <%= text_field_tag 'email', nil, class: 'form-control' %> </div> <div class="form-group"> <label>パスワード</label> <%= password_field_tag 'password', nil, class: 'form-control' %> </div> <div class="form-group text-center"> <%= submit_tag 'ログインする', class: 'btn btn-primary' %> </div> <% end %> </div> </div> </div>
users#new
ユーザー登録ページのViewとなります。
<div class="container"> <div class="row"> <div class="col-md-4"></div> <div class="col-md-4"> <% if @user.errors.any? %> <div id="error_explanation"> <h2><%= @user.errors.count %>件のエラーがあります。</h2> <ul> <% @user.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <%= form_for @user, url: { action: 'create' } do |f| %> <div class="form-group"> <%= f.label :name %> <%= f.text_field :name, class: 'form-control', required: true %> </div> <div class="form-group"> <%= f.label :email %> <%= f.email_field :email, class: 'form-control', required: true %> </div> <div class="form-group"> <%= f.label :password %> <%= f.password_field :password, class: 'form-control', required: true %> </div> <div class="form-group"> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'form-control', required: true %> </div> <div class="form-group text-center"> <%= f.submit '登録する', class: 'btn btn-primary' %> </div> <% end %> </div> </div> </div>
ここまで実装を行うと、ユーザー登録 -> ログイン -> ログアウトの一連の流れを確認することができます。