【Rails】ゲストユーザーのログイン機能(アカウント独立型)を実装する方法(Deviseなし)

ゲストユーザーとしてログインできる機能があれば、わざわざユーザー登録をしなくてもログインできるので便利ですよね。

気軽にお試しできるよう、ゲストログイン機能は是非とも実装しておきたいものです。

そこで今回はそのゲストログイン機能(Deviseなしで)を作ってみたので、実装する流れを忘れないうちにメモしておこうと思います。

Deviseでゲストログインを実装したい方はこちらの記事を参考にしてみてください。

あわせて読みたい
【Rails7】ゲストログイン機能を実装する方法(Devise実装済み) Rails7でポートフォリオ用のWebサイト(もしくは正式なWebサービス)にゲストログイン機能を実装したい。 ネットでググると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)

上記を忘れると後々面倒なことになる可能性があります。(詳しくは以下を参照)

Qiita
【Rails】booleanとは - Qiita ##booleanとはbooleanとは、一般的には真と偽のような2つの状態を表すデータ型。stringやintegerのようにマイグレーションファイルに記述することができる。##boolean…

マイグレーションファイルを編集し終えたらマイグレーションを実行します。

$ 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"ゲストユーザー"という名前に固定にしました。

あわせて読みたい
【Rails】各種idをランダムな文字列に変換してPrimary keyとして使う Railsでデータベースに値を登録すると、デフォルトでは各テーブルのid(integer型)が1から順番に割り当てられるようになっています。 しかし、このままだと(以下の例...

また今回の場合、ユーザー登録時の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_userlog_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} %>

これで、ゲストユーザーとしてログインし、一般ユーザーと同様に記事の投稿や編集、ユーザーのマイページへのアクセス、およびログアウトすることができるようになりました。

以上です。

参考記事

Qiita
[Ruby on rails]ゲストログイン機能 ゲストログインは削除、編集されないようにする - Qiita ゲストログインは作っておいた方が良い!ゲストログイン押したら、ログインできちゃう便利機能です。就職、転職活動でポートフォリオを外部の方に見せる場合には、作ってお...
blog.aiandrox
ゲストログインについての議論の過程 よくあるゲストログイン ゲストユーザーをあらかじめ作成しておいて、そのユーザーとしてログインする。 Sorceryを使った実装を例とする。 1 2 3
Qiita
has_secure_passwordのvalidationsをカスタマイズする - Qiita railsのhas_secure_passwordで自分の思い通りにvalidationを操作できないかと思って書いたメモ。おさらい:has_secure_passwordとは?ざっくり書くと、…
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

愛知の34歳。無職で暇になり始めたプログラミング(Ruby on Rails)の忘備録をまとめたブログです。最近は別にやりたいことができたのでプログラミングほぼやっていません。気が向いたらまた再開するかも。僕の日常はメインブログの方で更新しています。

コメント

コメントする

目次