🔥

deviseを使ってゲストログイン機能を実装する

に公開

はじめに

こんにちは!bosatoです!
この記事は30代未経験でwebエンジニアを目指し、現在スクールで勉強中の私が、勉強中にカリキュラムでは理解が難しかったことや、これってどうなの?って部分をアウトプットのために書いている記事です。この記事が僕と同じ境遇の人の役に立てば幸いです。

最近クラウドを勉強して、だんだん用語の意味を忘れてきてしまったり、ごちゃごちゃになってきたので必要最低限の知識を整理の意味でアウトプットしていこうと思います。

仕様の確認

  • トップページにゲストログイン機能を作成する
  • ゲストログインボタンを押すと、ゲストユーザーでログイン状態になり、ユーザー詳細画面へ遷移する
  • nameとemailは決めておく
  • ゲストログインユーザーはプロフィール編集画面への遷移ボタンを配置しない
  • ゲストログインユーザーはプロフィール編集画面へ遷移できない
  • 前提としてDeviseの機能を応用して実装する

ゲストログイン機能の作成

deviseのログイン機能はsessions_controller.rbに記載されており、このdeviseの機能を継承してゲストログイン機能を実装していきます。

アクションの定義

  1. app/controllersの配下にusersフォルダを作成し、sessions_controller.rbを作成。
    *adminも作成している場合は、publicフォルダにすることが多い
  2. sign_in userでゲストをログイン状態にさせる
app/controllers/users/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController
  def guest_sign_in
    user = User.guest
    sign_in user
    redirect_to user_path(user), notice: "guestuserでログインしました。"
  end
end

ルーティングの設定

config/routes.rb
devise_scope :user do
    post "users/guest_sign_in", to: "users/sessions#guest_sign_in"
  end

modelに記述

app/models/user.rb
:
:
  GUEST_USER_EMAIL = "guest@example.com"

  def self.guest
    find_or_create_by!(email: GUEST_USER_EMAIL) do |user|
      user.password = SecureRandom.urlsafe_base64
      user.name = "guestuser"
    end
  end
end

user.rbにapp/controllers/users/sessions_controller.rbで記述したUser.guestのguestメソッドを定義しています。
find_or_create_by!はデータの検索と作成を指導的に判断して処理を行うメソッド。
パスワードはSecureRandom.urlsafe_base64でランダムな文字列にすることができる。
name部分わかりやすいようにguestuserにします。
機能部分の作成は以上になります。

ゲストログインボタンを配置する

ログインボタンと新規作成ボタンの上に配置することにします。

app/views/homes/top.html.erb
<%= link_to "ゲストログイン(閲覧用)", users_guest_sign_in_path, method: :post %>

ここまででゲストログイン機能の実装は完了です。

プロフィール編集を行えないようにする

やること

  • ゲストユーザーでログインしているときにはプロフィール編集画面のボタンを表示しない
  • 編集画面へのURL直打ちにも対応させる

Viewの編集

app/views/users/***.html.erb
<% if user.email != "guest@example.com" %>
 <%= link_to edit_user_path(user) %>
<% end %>

***は自分の環境に合わせましょう。
ユーザーのemailがguest@example.comではない場合には、ボタンを表示して、ユーザーのemailがguest@example.comである場合には、表示しないようにします。

他にも

<% if !user.guest_user? && user == current_user %>
  <%= link_to "プロフィール編集", edit_user_path(user) %>
<% end %>

対象のuserがゲストユーザーではなく、かつ、現在ログインしているユーザーと同じである場合という条件分岐もできます。このコードでも成立しました。

直打ち対策

ユーザーの編集画面へのURLを直接入力された場合にはメッセージを表示してユーザー詳細画面へリダイレクトさせます。
app/controllers/users_controller.rbへメソッドを作成し、before_actionでeditアクション実行前に処理を行います。

app/controllers/users_controller.rb
class UsersController < ApplicationController
 before_action :ensure_guest, only: [:edit]
 :
 :
  
 private

 :
 :  

 def ensure_guest_user
  @user = User.find(params[:id])
  if @user.email == "guest@example.com"
   redirect_to user_path(current_user) , notice: "ゲストユーザーはプロフィール編集画面へ遷移できません。"
  end
 end  
end

次にapp/controllers/users_controller.rbとapp/views/users/***.html.erbでゲストユーザーであるかの判別をしているので、この判定処理をapp/models/user.rbにインスタンスメソッドとして定義して利用していきます。

```ruby
app/models/user.rb
:
:
 
GUEST_USER_EMAIL = "guest@example.com"
 
  def self.guest
    find_or_create_by!(email: GUEST_USER_EMAIL) do |user|
      user.password = SecureRandom.urlsafe_base64
      user.name = 'guestuser'
    end
  end
 
  def guest_user?
    email == GUEST_USER_EMAIL
  end
:
:

guest_user?というメソッドでは、メールアドレスがゲストユーザーのものであるかを判定しtrueかfalseの値を返します。
これを条件分岐に使用し、コードをブラッシュアップします。

app/controllers/users_controller.rb
:
:

  private

  :
  :  

  def ensure_guest_user
    @user = User.find(params[:id])
    if @user.guest_user?
      redirect_to user_path(current_user) , notice: 'ゲストユーザーはプロフィール編集画面へ遷移できません。'
    end
  end 

:
:
app/views/users/***.html.erb
:
:

<% unless user.guest_user? %>
  <%= link_to '',edit_user_path(user) %>
<% end %>

guest_user?というメソッドを定義することで、複数の箇所で同じメソッドを共有することができます。

まとめ

  1. controllerにアクション定義
  2. routes.rbを編集 devise_scope
  3. modelsにguestメソッドを定義
  4. viewにゲストログインボタンを設置
  5. viewにプロフィール編集を行えないよう条件分岐書く
  6. controllerにbefore_actionで直打ち対策する
  7. コードをブラッシュアップ

Discussion