[Rails]複数権限でのdeviseを用いたゲストログイン機能の実装
複数権限(例:Admin,Member等..)でゲストログイン機能を作ろうと思った時にroutes周辺でエラーになって困ったので残しておきます。
前提
- devise導入済み
- Admin,Member をdeviseで用いている。
行いたいこと
- ゲストユーザーとしてログインできるようにする。
- プロフィールの編集機能の制限(nickname等を変更されてしまうとログインできなくなってしまう為)
ルーティングの設定
まずはじめにゲストログイン用にルーティングをconfig/routes.rb
に記述します。
Rails.application.routes.draw do
...
devise_scope :member do
post "members/guest_sign_in", to: "public/sessions#guest_sign_in"
end
...
end
devise_scope
は、deviseを使用して新しくルーティングを指定したい時に必要となります。
ここではsign_in
のHTTPメソッドはユーザ情報をサーバへ送るので"POST"になります。
その右に実際の任意のURLの指定を行います。ここではわかりやすくguest_sign_in
としています。
to:
の後はコントローラーのアクションの指定となり、今回はpublic/sessions_controller.rb
にゲストログインアクションを記述していきます。
members_guest_sign_in POST /members/guest_sign_in(.:format) public/sessions#guest_sign_in
ルーティングの確認ができました。
アクションを定義する
わかりやすく以下のguest_sign_in
のようにアクションを定義します。
# frozen_string_literal: true
class Public::SessionsController < Devise::SessionsController
# before_action :configure_sign_in_params, only: [:create]
def guest_sign_in
member = Member.guest
sign_in member
redirect_to members_path, notice: "Guestでログインしました。"
end
...
end
※guest
メソッドはこの後Memberモデルに定義をしていきます。
アクション内で使用しているsign_in
メソッドはdeviseが提供している機能でサインイン状態にしてくれる便利なメソッドです。
最後にリダイレクト先とお好みでサクセスメッセージを指定します。
モデルに定義する
先ほどのguest
メソッドをMemberモデルに定義していきます。
class Member < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
...
GUEST_MEMBER_EMAIL = "guest@example.com"
def self.guest
find_or_create_by!(email: GUEST_MEMBER_EMAIL) do |member|
member.password = SecureRandom.urlsafe_base64
member.nickname = "guestmember"
end
end
def guest_member?
email == GUEST_MEMBER_EMAIL
end
...
end
この後ゲストかどうかを判定する時にこのアドレス(guest@example.com
)を記述する場面が多くあり、処理の度に同じ記述を書くとメールアドレスを変更したい時等に修正に弱いコードとなってしまいます。ここではRailsのDRY原則に則り、以下のようにGUEST_MEMBER_EMAIL
にメールアドレスを代入し汎用性の高いコードを意識します。"GUEST_MEMBER_EMAIL = guest@example.com
"
find_or_create_byとは?
こちらはRailsのメソッドで、データの検索と作成を自動的に判断して処理を行ってくれます。
今回は条件として(email: GUEST_MEMBER_EMAIL)
を与えています。
処理としては、まず条件として指定したデータが存在するかを判断し、存在したらそのデータを返し、存在しなければ新規作成をしてくれます。判断と処理をこのメソッドで行えるので便利なメソッドです。
find_or_create_by
の末尾に!
をつけているのは処理が成功しなかった時にエラーが発生しやすくなるためにつけています。これにより不具合を検知しやすくなります。
SecureRandom.urlsafe_base64とは?
こちらはRubyのメソッドの一種で、ランダムな文字列を生成してくれます。
こちらを使いパスワードを生成します。
今回のmembersテーブルにはnickname
カラムを作ってあるのでそちらをguestuser
と固定します。
下のguest_member?
メソッドはviewでゲストユーザーには表示させたくないもの(編集ボタン等)を条件分岐で表示させないようにする時に使うため、ここで定義しておきます。
ここまでで機能部分の作成は完了しました。
ビューファイルを編集する
まず任意の場所にゲストログインボタンを配置します。
<ul>
<% unless member_signed_in? %>
...
<li>
<%= link_to 'ゲストログイン', members_guest_sign_in_path, method: :post %>
</li>
...
<% end %>
</ul>
今回はヘッダーに配置しました。Topページ等でも良いと思います。
次にプロフィールの編集制限をしていきます。
<% if current_member.guest_member? %>
<%= image_tag current_member.get_icon(150,150) %>
<% else %>
<%= link_to members_information_edit_path do %>
<%= image_tag current_member.get_icon(150,150) %>
<p>編集</p>
<% end %>
<% end %>
今回はアイコンを編集ボタンとして設置していたので先程Memberモデルに定義したguest_member?
を使いゲストユーザーの場合には編集ページへのリンクを表示させないように条件分岐させます。
最後に編集画面のURLから直接編集画面に行けないようにします。
class Public::MembersController < ApplicationController
before_action :ensure_guest_member, only: [:edit]
...
private
...
def ensure_guest_member
if current_member.guest_member?
redirect_to member_path(current_member), notice: "ゲストユーザーはプロフィール編集できません。"
end
end
end
members_controllerへensure_guest_member
と定義します。こちらも任意で名前を変えていただいて大丈夫です。'before_action'でeditアクション実行前にこの処理を行わせます。
これでURLを直接叩かれても編集画面へ遷移できないようにできました。
こちらで実装は以上となります。
最後に
再び自分で記事を書いてみて、改めてたくさん投稿されている方に尊敬の念がつきません。。
時間を作り、もっと記事を投稿したいと思います。
学習のアウトプットと振り返りがメインですが、どなたかの参考になれば幸いです。。
なにか間違い(誤字脱字、技術面等)があればご指摘ください。
最後まで見てくださりありがとうございました。一緒に勉強がんばりましょう!
Discussion
今後実装するだろう機能なのでめちゃめちゃ助かります!
参考にさせてもらいます♪
そう言っていただけると嬉しいです!
為になるような情報をアップロードできるよう精進いたします😁