プログラミング学習記録

主にRuby on Railsを使ったプログラミングを学んでいます。

sorceryを使用して、ユーザー登録・ログイン機能を作成

sorceryとは

Railsに認証機能を実装するためのライブラリ。

インストール

Gemfileに

gem 'sorcery'

と書きターミナルでbundle installを実行。

初期設定

$ bundle exec rails g sorcery:install

これで必要最低限なファイルが作成される。

  • config/initialize/sorcery.rb
  • db/migrate/20xxxxxxxx_sorcery_core.rb
  • app/models/users.rb

など

マイグレーションファイル(db/migrate/20xxxxxxxx_sorcery_core.rb)には、必要最低限のカラム(eメール、パスワード等)がすでに定義されている。ここに適宜必要なカラム(例えば氏名など)を追加しデータベースに反映させる。

bundle exec rails db:migrate

または

rake db:migrate

を実行する。
(ちなみに、bundle execはBundlerが管理するGemを利用できる状態でコマンドを実行するということ)

コントローラを設定

$ bundle exec rails g sorcery:installを実行した事で、app/models/users.rbは作成されているが、usersコントローラは自分で作成する。

$ rails g controller users

を実行。
app/controllers/users_controller.rb

class UsersController < ApplicationController
  # ...
  private

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

また

$ rails g controller UserSessions new create destroy

でuser_sessions.controller.rbを作る。
app/controllers/user_sessions.controller.rb

class UserSessionsController < ApplicationController
  def create
    @user = login(params[:email], params[:password])

    if @user
      redirect_back_or_to(:users, notice: 'Login successful')
    else
      flash.now[:alert] = 'Login failed'
      render :new
    end
  end

  def destroy
    logout
    redirect_to(:users, notice: 'Logged out!')
  end
end

リダイレクト先やフラッシュなどは仕様に合わせて変更すれば良い。
usersコントローラでユーザー情報、user_sessionsコントローラでログイン/ログアウトに関する情報を扱う。

ルーティングを設定

config/routes.rb

root 'users#index'
resources :users

get 'login', to: 'user_sessions#new'
post 'login', to: 'user_sessions#create'
delete 'logout', to: 'user_sessions#destroy'

例えば、users_contoroller.rbでnewアクションとcreateアクションしか設定しないのであれば、
resources :users, only %i[new create]という書き方もできる。

※リソースベースのルーティングを設定すると、URL用のヘルパーを使用することができるようになる。(login_pathのようなやつ)

モデル

app/models/users.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

ログインフォーム

入力用のフォーム(パスワードがデータベースで暗号化される前にパスワードを保持しておくためのもの)
app/views/users/_form.html.erb

<div class="field">
   <%= form.label :password %><br />
   <%= form.password_field :password %>
</div>
<div class="field">
   <%= form.label :password_confirmation %><br />
   <%= form.password_field :password_confirmation %>
</div>

ログイン用のフォーム
app/views/user_sessions/new.html.erb

<h1>Login</h1>

<%= render 'form' %>

<%= link_to 'Back', users_path %>

app/views/user_sessions/_form.html.erb

<%= form_with url: login_path, method: :post do |f| %>
  <div class="field">
    <%= f.label :email %><br />
    <%= f.text_field :email %>
  </div>
  <div class="field">
    <%= f.label :password %><br />
    <%= f.password_field :password %>
  </div>
  <div class="actions">
    <%= f.submit "Login" %>
  </div>
<% end %>

あとは、app/views/layouts/application.html.erbにナビゲーションリンクとフラッシュメッセージを表示するためのビューを用意する(もちろんフラッシュ用のパーシャルを作っても良い)。そこにログアウト用のリンクを作る。
注意:logoutのリンクでmethod: :deleteを指定し忘れないようにする。
そして、ユーザー登録用のビューをapp/views/users/new/html.erbとして作成する。

ログインしていないユーザーの権限を制限

sorceryには便利なメソッドが用意されている。
require_login(sorceryが用意しているので自分で定義しなくて良い)
ログインしていない状態だとログインページへリダイレクトさせる

# app/controllers/application_controller.rb
# 全てのアクションが呼び出される前にrequire_loginメソッドを呼び出す
before_action :require_login

# app/controllers/users_controller.rb
# users_controllerのindex,new,createアクションが呼び出されるときは、require_loginを呼び出さない
skip_before_action :require_login, only: [:index, :new, :create]

# app/controllers/user_sessions_controller.rb
skip_before_action :require_login, only: [:new, :create]

参考サイト

Simple Password Authentication · Sorcery/sorcery Wiki · GitHub