はじめに
今回はゲストログイン機能について学習していきたいと思います。
以下,Devise
を使用している前提とし,トップページが root 'homes#index'
で設定されていることとします。
流れ
①ゲストユーザーをデータベースから取り出す
②そのユーザーをログインさせる
③フラッシュメッセージを出してトップページへリダイレクト
#1.ゲストログイン機能の実装方法(簡易版)
ゲストログイン用のアクションを作成
# 以下を追加
post '/homes/guest_sign_in', to: 'homes#new_guest'
# 以下を追加
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
# 以下を追加
<%= link_to 'ゲストログイン(閲覧用)', homes_guest_sign_in_path, method: :post %>
ポイントはDeviseのsign_inメソッドを利用することです。
-
find_byではなく,find_or_create_byを利用しています。これにより,ゲストユーザーをあらかじめ作成する手間を省けます。また,ゲストユーザーを削除されてゲスト機能が動作しなくなるリスクも回避できます。(コードではゲストユーザーがあればそれを取り出す。なければ新しく作成する設定をしている)
-
パスワードを特定されると,ユーザー編集ページからメールアドレス・パスワードを変更される可能性があるため,パスワードはランダム文字列にしています。
user.password = SecureRandom.urlsafe_base64
-
バリデーションの影響でゲストユーザーを作成できない場合は,エラーを発生させるように設定しております。
- 例えば, name が必須であれば,user.name = "take" などを追加して下さい
#2.ゲストログイン機能の実装方法
上記の実装方法は理解しやすいものの,ゲストログイン機能をHomesController
に任せることには違和感があります。本来は,ログイン機能同様,Devise
のSessionsController
に任せるべきでしょう。
例えば次のように実装すると,より自然なものになるのではないでしょうか。
ゲストログイン機能の設定
まず,SessionsController
に新しいアクションnew_guest
を準備します。
# 以下を追加
devise_scope :user do
post 'users/guest_sign_in', to: 'users/sessions#new_guest'
end
アクションnew_guestを設定するため,app/controllers
にusers
ディレクトリを作成し,その中に次のsessions_controller.rb
を作成します。ゲストユーザーを探す or 作成する機能はUser.rb
に移動させるとコントローラーがスッキリします。
class Users::SessionsController < Devise::SessionsController
def new_guest
user = User.guest
sign_in user
redirect_to root_path, notice: 'ゲストユーザーとしてログインしました。'
end
end
# 以下を追加
def self.guest
find_or_create_by!(email: 'guest@example.com') do |user|
user.password = SecureRandom.urlsafe_base64
# user.confirmed_at = Time.now # Confirmable を使用している場合は必要
end
end
トップページにゲストログインボタンを用意する場合は,以下を追加すればOKです。(スタイルは各自で追加して下さい)
# 以下を追加
<%= link_to 'ゲストログイン(閲覧用)', users_guest_sign_in_path, method: :post %>
ゲストユーザーを削除できないようにする
上記の実装方法ならば,仮にゲストユーザーを削除されたとしても,ゲスト機能が動作しなくなることはありません。
ですが,例えば2名の方が同時にログインされている状態で,片方の方がゲストユーザーを削除しますと,もう片方の方も強制的にログアウトさせられてしまいます。ポートフォリオの場合はレアケースだと思いますが,念のためゲストユーザーを削除できないように設定しておきましょう。
ゲストユーザーが削除機能を使用できないようにするには,registrations.rb
を編集する必要があります。まずは,ルーティングを変更します。
# devise_for :users を次に置き換える
devise_for :users, controllers: {
registrations: 'users/registrations'
}
destroy
アクションの動作前に,メールアドレスがゲストユーザー用になっていないかチェックするように設定します。
ゲストユーザーならばフラッシュを出した上でトップページにリダイレクトさせるように設定しています。
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
ゲストユーザーがパスワードやメールアドレスを編集できないようにする
上記の実装ならば,「ユーザー編集機能」や「パスワード再設定機能」によりメールアドレス・パスワードを変更される可能性は非常に低いですし,仮に変更されたとしてもポートフォリオならば問題にならないかと思います。
それでも,「ゲストユーザーのメールアドレス・パスワードを絶対に変更されたくない!」という場合は,更に次のような設定をすればOKです。
削除機能を止めるのと同じ手法で,ゲストユーザーがメールアドレス・パスワードを編集できないように設定します。
- 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です。まずはルーティングを変更します。
# devise_for :users, controllers: {
# registrations: 'users/registrations'
# }
# を次に置き換える。(,の付け忘れに注意!)
devise_for :users, controllers: {
registrations: 'users/registrations',
passwords: 'users/passwords'
}
パスワード再設定ページのフォームに入力されたメールアドレスはparams[:user][:email]で受け取れるので,これを利用してゲストユーザーを特定します。
メールアドレスは大文字が小文字に変換されて保存されているため,downcaseメソッドが必要です。
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です。
# 次を追加
# 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
最後に
一応これでゲストログイン機能の完成です。
何か間違っているところがあればご教授していただけると幸いです。