fv17の日記

Webエンジニアの備忘用ブログです。主にWeb界隈の技術に関して書いています。

Rails - フレンドリーフォワーディング

はじめに

詳細は、Rails tutorial 第10章の「フレンドリーフォワーディング」を参照。
https://railstutorial.jp/chapters/updating_and_deleting_users?version=5.1#sec-friendly_forwarding

Tutorialですぐに理解できなかったので復習用としてまとめてみました。
理解できれば簡単ですが、初見で見ると実装が何やっているのか分かりづらい...

求める仕様

未ログイン状態で権限のないページをリクエストした場合を想定。
この場合、下記のような仕様にしたい。

  1. まず、ログインページに遷移する
  2. 次に、ログインが完了後、先ほどリクエストしたページへ遷移する

つまり、通常のログイン時と同じ遷移先ではなく、
ユーザーがログイン前に見たかったページに遷移させるようにする。

上記を実現するために必要なメソッド

アクセスしようとしたURLを覚えておくメソッド(store_location)
ログイン済みか判定するロジックにおいて、未ログインならば store_location が呼ばれ、
ユーザーが見たかったページを一旦覚えておく。

覚えておいたページへリダイレクトするためのメソッド(redirect_back_to)
ログイン時のリダイレクト先として redirect_back_to を呼び出し、
store_locationで覚えているURLが存在すればそちらに遷移。
存在しない場合は通常のログインの場合と同じURLへ遷移。

SessionsHelperにメソッドを追加

次の2つのメソッド

# アクセスしようとしたURLを覚えておく
def store_location
  session[:forwarding_url] = request.original_url if request.get?  # GETリクエストの時のみ
end

# 覚えておいたページへリダイレクト
def redirect_back_or(default)
  redirect_to(sessions[:forwarding_url] || default)
  session.delete(:forwarding_url)
end

store_location は、ログイン済みか判定するロジックにおいて呼ばれる

class UsersController < ApplicationController
  before_action :logged_in_user, only[:edit, :update]
  .
  .
  private
  .
  .
    def logged_in_user
      unless logged_in?
        store_location  # ★ここで呼ばれ、未ログイン状態の時に遷移先を覚えておく
        flash[:danger] = "ログインしてください。"
        redire_to_ login_url
      end
    end
end

redirect_back_or は、ログインに成功した直後に呼ばれる

store_locationで覚えているURLが存在すればそちらに遷移。
存在しない場合は通常のログインの場合と同じURLへ遷移。

メソッドの名称がいいですね。引数をorの目的語(補語?)にしている。

class SessionsConroller < ApplicationController
  .
  .
  .
  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      log_in user
      redirect_back_or user  # ★ログインに成功した場合、遷移先を決定する
    else
      flash.now[:danger] = 'メールとパスワードの組み合わせが正しくありません。'
      render 'new'
    end
  end
  .
  .
  .
end