ゲストユーザーとしてログインできる機能があれば、わざわざユーザー登録をしなくてもログインできるので便利ですよね。
気軽にお試しできるよう、ゲストログイン機能は是非とも実装しておきたいものです。
そこで今回はそのゲストログイン機能(Deviseなしで)を作ってみたので、実装する流れを忘れないうちにメモしておこうと思います。
Deviseでゲストログインを実装したい方はこちらの記事を参考にしてみてください。
作成するゲストログインのパターンと出来上がりイメージ
ゲストログイン機能には、以下の2種類のパターンがあると思っています。
パターン1はゲストアカウントをそれぞれ独立させるパターンで、ゲストアカウント同士のIDを分けたい場合などに有効です。
パターン2は1つのゲストアカウントを、ゲストログインユーザーで共有するパターンで、通常はこちらのパターンが多く用いられるかと思います。
ただ、今回は僕のポートフォリオの1つでもあるQRコード宝探しゲームアプリへの実装の都合上、「パターン1」の独立型のゲストログイン機能を実装することにしました。
(当記事ではパターン1のゲストログイン機能の実装について解説していきます。パターン2の実装方法についてはこちらの記事をご覧ください。)
今回実装するゲストログイン機能の動作イメージは以下の通りです↓
- ゲストユーザー専用ログインボタンで即時ログインできる
- 一般ユーザーと同じように投稿・編集できる
- ユーザーページに自分の投稿一覧を表示する
- 一般ユーザーとゲストユーザーを判別できるようにする
- ログアウトできる(一度ログアウトしたら再度同じゲストアカウントにはログインできない)
ゲストログイン機能を実装する流れ
それでは、ゲストユーザーとしてログインする機能を実装していきます。
usersテーブルにゲストユーザー判別用のカラム”guest”を追加する
一般ユーザーとゲストユーザーを判別できるよう、usersテーブルにguestカラム(型はboolean)を追加します(判別の必要がなければカラム追加する必要ありません)。
guestカラムにはデフォルトではfalse(データベース上では0)を、ゲストユーザー作成およびログイン時にはtrue(データベース上では1)を代入するよう、後で設定します。
class AddGuestToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :guest, :boolean, default: false, null: false
end
end
boolean型を追加する場合は、以下の2点に注意です。
- デフォルト値を設定しておく(falseにしておく)
- NOT NULL制約を設ける(null: false)
上記を忘れると後々面倒なことになる可能性があります。(詳しくは以下を参照)
マイグレーションファイルを編集し終えたらマイグレーションを実行します。
$ rails db:migrate
【任意】ゲストユーザーのみバリデーションを解除したい場合
ユーザーの本登録で、通常は何かしらのバリデーションをかけているかと思います。
しかし、ゲストユーザーとしてログインする場合もゲスト用のアカウントを作成することになるため、バリデーションをかけていると不都合が生じる場合があります。
例えば、「ユーザー名はユニークな半角英数字であること」というバリデーションを設けているが、ゲスト用のアカウント名は全て同一名(”GuestUser”など)に統一したいという場合はあるでしょう。
そんな時は、ゲストユーザー用のアカウント作成時のみバリデーションを適用外にする(下記コード参照)必要があります。
class User < ApplicationRecord
has_many :posts, dependent: :destroy
before_create :set_user_id
# ユーザー名のバリデーション
VALID_NAME_REGEX = /\A[a-zA-Z0-9]+\z/ # 半角英数字のみ受け付けるようにする
validates :name, presence: true, uniqueness: { case_sensitive: false },
length: { maximum: 30 },
format: { with: VALID_NAME_REGEX },
if: :require_validation?
# ↑ guestがtrueの場合のみ、バリデーションを除外する
・・・
private
・・・
#ゲストユーザーのみバリデーションを解除する(falseを返す)
def require_validation?
return true if self.guest == false || self.guest == 0
false
end
end
最初に追加しておいたゲストユーザー判別用のカラム”guest”を用いて、ゲストユーザーがtrueの場合(ゲストユーザーとしてログインした場合)のみfalseを返すようなメソッドrequire_validation?
を作成し、
任意のバリデーションの行にif: :require_validation?
を追記することで、ゲストユーザー作成時のみバリデーションを適用外にすることができます。
ゲストユーザーを作成するメソッドを追加
以下の条件でゲストユーザーを作成するメソッドをuser.rb
に追加します。
- idはランダムに生成(SecureRandomにて)
- ユーザー名は「ゲストユーザー」で固定
- メールアドレスがある場合は固定、もしくは一部ランダムで生成(今回は省略)
- パスワードはランダムに生成(その後、bcryptでハッシュ化)
- guestカラムをtrueに設定
class User < ApplicationRecord
has_many :posts, dependent: :destroy
before_create :set_user_id
・・・
private
# ランダムなユーザーIDを生成
def set_user_id
while self.id.blank? || User.find_by(id: self.id).present? do
self.id = SecureRandom.base58
end
end
# ゲストユーザーを作成する
def self.guest_login
random_pass = SecureRandom.base36
create!(name: "ゲストユーザー",
password: random_pass,
guest: true)
end
end
ゲストユーザーのname
はランダムに生成しても良いのですが、今回はゲストユーザー間の違いをid
(SecureRandomで生成したランダムな文字列)で判別するのと、password
もそれぞれランダムで生成しているため、
他のゲストユーザーと混合する心配はないと判断し、ゲストユーザーのname
は"ゲストユーザー"
という名前に固定にしました。
また今回の場合、ユーザー登録時のname
は半角英数字しか受け付けないようにしているため、
ゲストユーザー名をあえてカタカナ表記にすることで、データベースチェック時にパッと見で登録ユーザー(半角英数字)と"ゲストユーザー"
の見分けがつくようになっています。
ゲストユーザーとしてログインするアクションを追加する
ゲストユーザーを作成するメソッドを用いて、usersコントローラーにゲストユーザーとしてログインするアクションを追加します。
class UsersController < ApplicationController
・・・
def destroy
・・・
end
def guest_login
if current_user
redirect_to current_user, alert: "すでにログインしています" # ログインしている場合はゲストユーザーを作成しない
else
user = User.guest_login
log_in user
redirect_to user, notice: "ゲストとしてログインしました"
end
end
ここで、上記のようにすでにログインしている場合は、警告メッセージとともにログインしているユーザーページにリダイレクトするように条件分岐しておきます。
current_user
やlog_in
メソッドはapplication_controller.rb
に以下のように定義しておきます。(ついでにログアウト用のメソッドlog_out
も定義しておきます)
class ApplicationController < ActionController::Base
helper_method :log_in, :current_user, :log_out
# ログイン
def log_in(user)
session[:user_id] = user.id
end
# 現在ログイン中のユーザーのセッションを返すメソッド
def current_user
if(user_id = session[:user_id])
@current_user ||= User.find_by(id: user_id)
end
end
# ログアウト
def log_out
session.delete(:user_id)
@current_user = nil
end
end
ルーティングの設定をする
最後に、先ほど追加したアクションを実行するためのルーティングを設定します。
get "guest_login", to: "users#guest_login"
ルーティングを設定したら、「ゲストユーザーとしてログインする」ためのリンク(またはボタン)を設置したい箇所に設定したルーティングのパスを追記します。
<%= link_to "ゲストユーザーとして利用する", guest_login_path %>
ログアウト用のパスは一般ユーザー用のログアウトリンクと共通で問題ありません。
delete "logout", to: "sessions#destroy"
# Rails7.0 以降の表記法
<%= link_to "ログアウト", logout_path, data: { turbo_method: :delete} %>
これで、ゲストユーザーとしてログインし、一般ユーザーと同様に記事の投稿や編集、ユーザーのマイページへのアクセス、およびログアウトすることができるようになりました。
以上です。
コメント