目的
学んだことを忘れないように備忘録として残す
sorceryとは?
SorceryはRuby on Railsで使用できる認証および認可のGem。これを使用することで、ユーザー認証、パスワードリセット、ユーザー管理などの一般的な認証および認可機能をアプリケーションに簡単に統合できる。
gemとは?
gem は、Rubyプログラミング言語の拡張機能やライブラリをパッケージ化したもの。
RubyGemsを使用することで、他の開発者が書いたRubyライブラリやアプリケーションを簡単にインストールできる。
sorceryの追加
gemファイルにsorceryを追加
gem ‘sorcery’
gemの反映
bundle installで追加したgemファイルを反映
bundle install
sorceryのセットアップ
Sorcery gem用の設定ファイルと関連するファイルを生成
必要なファイルをプロジェクトに追加し、設定をカスタマイズできるようにする。
rails g sorcery:install
生成されるファイル
- config/initializers/sorcery.rb:Sorceryの設定ファイル
- app/controllers/user_sessions_controller.rb:ユーザーセッション(ログインとログアウト)を管理するためのコントローラー
- app/models/user.rb:ユーザーモデルのテンプレート。ユーザーに関連するメソッドや属性を追加する場合にこのファイルを編集する。
- app/views/user_sessions:ログインフォームやログアウトリンクなどのビューファイルが含まれる。
- db/migrate/*_create_users.rb(実際のファイル名はタイムスタンプによって異なる):ユーザーモデルに関連するデータベーステーブルを作成するマイグレーションファイル
マイグレーションファイルの更新
Sorceryを使ったユーザー認証システムが正しく動作し、データベースと連携できるようにする。
rails db:migrate
マイグレーションファイルの編集
ユーザ登録の際に姓名を入力できるようにしたいため、データベースにlast_name、first_nameカラムをstring型で追加
マイグレーションファイルの作成
rails g migration AddNameToUsers
作成したマイグレーションファイルを編集
class AddNameToUsers < ActiveRecord::Migration
def change
add_column :users, :last_name, :string
add_column :users, :first_name, :string
end
end
マイグレーションファイルの更新
作成したマイグレーションファイル(AddNameToUsers)に変更を加えたので、更新する。
rails db:migrate
Userモデルのバリデーション設定
app/models/user.rb
Userモデルにバリデーションを追加
class User < ApplicationRecord
authenticates_with_sorcery!
#ユーザーが設定したパスワードの長さが3文字以上であることを確認
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] }
#新規にユーザーが登録された際に、emailが存在するか、登録済みかどうかを確認
validates :email, uniqueness: true, presence: true
#新規にユーザーが登録された際に、first_nameが存在するかどうかの確認と文字数の制限
validates :first_name, presence: true, length: { maximum: 255 }
#新規にユーザーが登録された際に、last_nameが存在するかどうかの確認と文字数の制限
validates :last_name, presence: true, length: { maximum: 255 }
end
#confirmationは、2つの属性の値が一致するかどうかを検証
#presenceは、指定された属性が存在しているかどうかを検証
new_record?: レコードが新しいレコードかどうかを確認するメソッド
changes[:crypted_password]: レコードの crypted_password フィールドに変更があるかどうかを確認
ユーザー登録機能の作成
usersコントローラとビュー生成
rails g controller users new
app/controllers/users_controller.rbとapp/views/users/new.html.erbが生成される。
user_controllerへの記述
class UsersController < ApplicationController
def new; end
def create
# @userにuser_paramsに入ったデータを代入
@user = User.new(user_params)
if @user.save
#login_path ヘルパーメソッドで、保存が成功したらログインページへ飛ばす
redirect_to login_path
else
#保存が失敗したら登録画面へ飛ばす
render 'new'
end
end
private
#ユーザー登録画面からUserモデルへ送信されたパラメーターを要求し、その中からpermitで指定したパラメータを取得
def user_params
params.require(:user).permit(:last_name, :first_name, :email, :password,
:password_confirmation)
end
end
ユーザーの新規登録ページの作成
new.html.erbへの記述
form_withで投稿フォームを作成するときは、form.htmlタグ名 :カラム名
とする。 (カラム名は保存される先のテーブルのカラム名を指定)
上記の場合は、登録ボタンが押されたら、Userモデルの各カラムに入力内容が保存されるようする。
<div class="container">
<div class="row">
<div class="col-md-10 col-lg-8 mx-auto">
<h1>ユーザー登録</h1>
<%= form_with model: @user do |f| %>
<div class="mb-3">
# ユーザーがこのフォーム内の last_name テキストフィールドに入力した値が、
# フォームの送信時に last_name という名前のパラメーターとしてサーバーに送信される
<%= f.label :last_name, class: "form-label" %>
<%= f.text_field :last_name, class: "form-control" %>
</div>
<div class="mb-3">
<%= f.label :first_name, class: "form-label" %>
<%= f.text_field :first_name, class: "form-control" %>
</div>
<div class="mb-3">
<%= f.label :email, class: "form-label" %>
<%= f.email_field :email, class: "form-control" %>
</div>
<div class="mb-3">
<%= f.label :password, class: "form-label" %>
<%= f.password_field :password, class: "form-control" %>
</div>
<div class="mb-3">
<%= f.label :password_confirmation, class: "form-label" %>
<%= 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>
ルートの設定
config/routes.rb
Rails.application.routes.draw do
#ルートURLにアクセスされた場合、static_pages コントローラーの top アクションを呼び出す
root 'static_pages#top'
#/login にアクセスされた場合、user_sessions コントローラーの new アクションを呼び出す
get 'login', to: 'user_sessions#new'
#/login に対してHTTP POSTリクエストが送信された場合、user_sessions コントローラーの create アクションが呼び出す
post 'login', to: 'user_sessions#create'
#/logout に対してHTTP DELETEリクエストが送信された場合、user_sessions コントローラーの destroy アクションが呼び出す
delete 'logout', to: 'user_sessions#destroy'
#新規ユーザーの作成画面を表示する new アクションと、ユーザーの作成を行うcreateアクションを提供するためのURLが自動的に生成される
resources :users, only: %i[new create]
end
ログイン機能の作成
user_sessionsコントローラを生成します
rails g controller user_sessions
app/controllers/user_sessions_controller.rbが生成される。
UserSessionController にログインの処理を記述
app/controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
# require_loginフィルターを new と create アクションに適用しないように指示
# 新しいユーザーを作成するための new アクションと create アクションでは、ログインが必要ないことを示す
skip_before_action :require_login, only: %i[new create]
def new; end
def create
@user = login(params[:email], params[:password])
if @user
# ログインに成功した場合、root_pathにリダイレクト
redirect_to root_path
else
# ログインに失敗した場合、ログインページにリダイレクト
render :new
end
end
end
skip_before_action :require_login, only: %i[new create]を設定するのは、ログインを行う前にログインページにアクセスできて、ログインしていない状態でcreateアクションを実行する必要があるため。
ヘッダーの作成
ログイン前のヘッダーを作成して、ログイン・未ログイン状態によって表示を変えれるようにする。
まずは、ログイン・未ログイン状態でヘッダーが切り替わるように設定。
app/views/layouts/application.html.erb
<body>
<% if logged_in? %>
<%= render 'shared/header' %>
<% else %>
<%= render 'shared/before_login_header' %>
<% end %>
<%= yield %>
<%= render 'shared/footer' %>
</body>
未ログイン時のヘッダーを作成
app/views/shared/_before_login_header.html.erb
<header>
# ナビゲーションバーを定義するためのHTML要素を生成
<nav class="navbar navbar-expand-lg navigation navbar-light bg-light">
# ロゴ画像を表示するためのコード
<%= link_to root_path, class: "navbar-brand" do %>
<%= image_tag "#" %> # 任意の画像を入れる
<% end %>
# Bootstrapのナビゲーションバーでハンバーガーメニューを定義するためのHTML要素を生成
<button class='navbar-toggler' data-bs-toggle='collapse' data-bs-target='#navbarSupportedContent' aria-controls='navbarSupportedContent' aria-expanded='false' aria-label='Toggle navigation'>
<span class="navbar-toggler-icon"></span>
</button>
# ナビゲーションバーで折りたたみメニューを定義するためのHTML要素を生成
<div class="collapse navbar-collapse" id="navbarSupportedContent">
# ナビゲーションバーにメニュー項目を追加するためのHTML要素を生成
<ul class="navbar-nav ms-auto main-nav align-items-center">
# ログインというテキストにリンクを作成
<li class="nav-item">
<%= link_to 'ログイン', login_path, class: "nav-link" %>
</li>
</ul>
</div>
</nav>
</header>
ログイン時のヘッダーを作成
app/views/shared/_login_header.html.erb
<header>
<nav class="navbar navbar-expand-lg navigation navbar-light bg-light">
<%= link_to root_path, class: "navbar-brand" do %>
<%= image_tag "#" %> # 任意の画像を入れる
<% end %>
# Bootstrapを使用してナビゲーションバーのトグル(折り畳み)ボタンを作成
<button class='navbar-toggler' data-bs-toggle='collapse' data-bs-target='#navbarSupportedContent' aria-controls='navbarSupportedContent' aria-expanded='false' aria-label='Toggle navigation'>
<span class="navbar-toggler-icon"></span>
</button>
<div class='collapse navbar-collapse' id='navbarSupportedContent'>
<ul class='navbar-nav ms-auto main-nav align-items-center'>
<li class="nav-item">
# ユーザーがログアウトを実行した際には、UserSessionsController の destroy アクションが呼び出され、logout メソッドが実行される
<%= link_to 'ログアウト', logout_path, class: 'dropdown-item' %>
</li>
</ul>
</div>
</nav>
</header>
ログアウト機能の作成
UserSessionController にログアウトの処理を記述
app/controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
# require_loginフィルターを new と create アクションに適用しないように指示
# 新しいユーザーを作成するための new アクションと create アクションでは、ログインが必要ないことを示す
skip_before_action :require_login, only: %i[new create]
def new; end
def create
@user = login(params[:email], params[:password])
if @user
# ログインに成功した場合、root_path(トップページ)にリダイレクト
redirect_to root_path
else
# ログインに失敗した場合、ログインページにリダイレクト
render :new
end
end
def destroy
# logoutメソッドを呼び出して、セッションをクリアする
logout
# ログアウトに成功した場合、root_path(トップページ)にリダイレクト
redirect_to root_path
end
end