【Rails】ゲストログイン・簡単ログイン機能の実装

はじめに

ポートフォリオ用のWebサイトに必須と言われるゲストログイン機能。

特にDeviseのconfirmableを使用している場合は,ゲストログイン機能が無いと,新規登録が面倒という理由でポートフォリオを見てすらもらえない可能性が高くなります。

ところが,普通のWebサイトには導入しないためか,良い記事が見当たりませんでした。

今回は上記の記事を参考にしていきます。

以下,Deviseを使用している前提とします。


ゲストログイン機能の実装方法

上記の記事の方法ではゲスト機能を、ホームコントローラーを使用しているので新しくコントローラーを作成するのが良いと思います。

ターミナル

rails g controller guests

私は今回のポートフォリオで管理者側と顧客側で分かれていた為、
rails g controller public/guests と rails g controller admin/guests
で作成しています。

config/routes.rb
# 以下を追加

post '/guests/guest_sign_in', to: 'guests#new_guest'

app/controllers/guests_controller.rb  
# 以下を追加


 def new_guest
   user = User.find_or_create_by!(email: 'guest@example.com') do |user|
     user.password = SecureRandom.urlsafe_base64
     # user.confirmed_at = Time.now  # Confirmable を使用している場合は必要
   end
   sign_in user
   redirect_to root_path, notice: 'ゲストユーザーとしてログインしました。'
 end

userの変数はcustomerなどに変える事ができます。
emailとパスワードの他にユーザー情報を持っている場合は、emailの後にデータを入れてください。(バリデーションがかかっていなければなくてもOKですが)


app/views/layout/application.html.erb
# 以下を追加

完成!ログインが出来るか確かめてください。

<%= link_to 'ゲストログイン(閲覧用)', guests_guest_sign_in_path, method: :post %>


ポイントはDeviseのsign_inメソッドを利用することです。

find_byではなく,find_or_create_byを利用しています。これにより,ゲストユーザーをあらかじめ作成する手間を省けます。また,ゲストユーザーを削除されてゲスト機能が動作しなくなるリスクも回避できます。

パスワードを特定されると,ユーザー編集ページからメールアドレス・パスワードを変更される可能性があるため,パスワードはランダム文字列にしています。

バリデーションの影響でゲストユーザーを作成できない場合は,エラーを発生させるように設定しております。

ゲストユーザーが削除機能を使用できないようにするには,registrations.rbを編集する必要があります。まずは,ルーティングを変更します。

config/routes.rb

# devise_for :users を次に置き換える
 devise_for :users, controllers: {
   registrations: 'users/registrations'
 }


destroyアクションの動作前に,メールアドレスがゲストユーザー用になっていないかチェックするように設定します。
ゲストユーザーならばフラッシュを出した上でトップページにリダイレクトさせるように設定しています。


app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
 before_action :check_guest, only: :destroy
 def check_guest
   if resource.email == 'guest@example.com'
     redirect_to root_path, alert: 'ゲストユーザーは削除できません。'
   end
 end
end


2-3 ゲストユーザーがメールアドレス・パスワードを変更できないようにする
上記の実装ならば,「ユーザー編集機能」や「パスワード再設定機能」によりメールアドレス・パスワードを変更される可能性は非常に低いですし,仮に変更されたとしてもポートフォリオならば問題にならないかと思います。

それでも,「ゲストユーザーのメールアドレス・パスワードを絶対に変更されたくない!」という場合は,更に次のような設定をすればOKです。

削除機能を止めるのと同じ手法で,ゲストユーザーがメールアドレス・パスワードを編集できないように設定します。
app/controllers/users/registrations_controller.rb

- before_action :check_guest, only: :destroy
+ before_action :check_guest, only: %i[update destroy]
- redirect_to root_path, alert: 'ゲストユーザーは削除できません。'
+ redirect_to root_path, alert: 'ゲストユーザーの変更・削除はできません。'


パスワード再設定メールの送信機能を止めるには,passwords_controller.rbのcreateアクションの動作前にチェックすればOKです。まずはルーティングを変更します。
config/routes.rb

#   devise_for :users, controllers: {
#     registrations: 'users/registrations'
#   }
# を次に置き換える。(,の付け忘れに注意!)
 devise_for :users, controllers: {
   registrations: 'users/registrations',
   passwords: 'users/passwords'
 }


パスワード再設定ページのフォームに入力されたメールアドレスはparams[:user][:email]で受け取れるので,これを利用してゲストユーザーを特定します。
メールアドレスは大文字が小文字に変換されて保存されているため,downcaseメソッドが必要です。


app/controllers/users/passwords_controller.rb


class Users::PasswordsController < Devise::PasswordsController
 before_action :check_guest, only: :create
 def check_guest
   if params[:user][:email].downcase == 'guest@example.com'
     redirect_to root_path, alert: 'ゲストユーザーの変更・削除はできません。'
   end
 end
end


【補足】 check_guestがほぼ同じ内容ですので,次のようにまとめてしまってもOKです。

app/controllers/application_controller.rb
# 次を追加
# registrations_controller.rb と passwords_controller.rb の check_guest は削除


 def check_guest
   email = resource&.email || params[:user][:email].downcase
   if email == 'guest@example.com'
     redirect_to root_path, alert: 'ゲストユーザーの変更・削除はできません。'
   end
 end


備考
上記はあくまで最低限度の実装です。例えば,ゲストユーザーの情報は他の利用者にも引き継がれますので,必要があればTrackableを入れて,current_sign_in_atを基準に次のような実装をしてもよいかもしれません。

定期的にデータを初期化する設定を入れる
ゲストユーザーを複数用意して,現在ログイン日時の最も古いゲストユーザーでログインする
実は,最初,devise/sessions/new.html.erbの真似をして,hidden_fieldを加えて……という手順で実装しようとしました。ところが,この方法ではuser_email, user_passwordなどのidセレクタが重複するエラーが出てしまいます。そこで,sign_inメソッドの存在を思い出し,このような実装方法にたどりつきました。


この記事が気に入ったらサポートをしてみませんか?