Deviseでresource毎にログイン後のリダイレクト先を変えたい場合の自分なりの対応

最終更新日

アイキャッチ

皆さんdevise使っていますか?
Railsの認証にはdeviseがデファクトスタンダードになっていますよね。
今回は、deviseの認証で「user」と「admin」などのように違うresourceでログインしたあとのリダイレクト先の設定方法について自分なりの考えを記載しようと思います。

目次

  1. 環境
  2. リダイレクト先の設定方法
    • resource毎のroot_pathを適切に定義する
    • なぜこれでresource毎にリダイレクトされるのか?
    • 参考: devise-4.7.3/lib/devise/controllers/helpers.rb
    • 参考: 調べるとよく出てくるパターン
  3. なぜそう考えるのか?
    • ログインやサインアップ、パスワード更新、などの度に設定する必要がでてくる
    • 余計なコードは少ないほうが良い
  4. では調べるとよく出てくるパターンはいつ使うべきなのか?
  5. まとめ

1. 環境

  • rails: 6.1
  • devise: 4.7.3

2. リダイレクト先の設定方法

調べるとよく出てくるapplication_controller.rbでafter_xxx_path_forを上書きするのではなく、「resource毎のroot_pathを適切に定義する」という対応方法が良いのではないか?と思っています。

resource毎のroot_pathを適切に定義する

config/routes.rb

namespace :admin do
  resource :dashboard, only: :show, as: :root
end

bin/rails routes | grep admin

admin_root GET /admin/dashboard(.:format) admin/dashboards#show

このように、config/routes.rbで適切にnamespace, scope, moduleなどを切ってas: :rootを定義するとadmin_root_pathが定義され、ログイン後にそれぞれのresource毎に好きな画面に遷移させることができます。

なぜこれでresource毎にリダイレクトされるのか?

deviseでは以下のsigned_in_root_path の通り、user_root_pathadmin_root_pathなどのresource毎のroot_pathが定義されていると、それを最優先して実行するためです。

参考: signed_in_root_path

devise-4.7.3/lib/devise/controllers/helpers.rb

# The scope root url to be used when they're signed in. By default, it first
# tries to find a resource_root_path, otherwise it uses the root_path.
def signed_in_root_path(resource_or_scope)
  scope = Devise::Mapping.find_scope!(resource_or_scope)
  router_name = Devise.mappings[scope].router_name

  home_path = "#{scope}_root_path"

  context = router_name ? send(router_name) : self

  if context.respond_to?(home_path, true)
    context.send(home_path)
  elsif context.respond_to?(:root_path)
    context.root_path
  elsif respond_to?(:root_path)
    root_path
  else
    "/"
  end
end

参考: 調べるとよく出てくるパターン

app/controllers/application_controller.rb

def after_xxx_path_for
  #{リダイレクト先}
end

3. なぜそう考えるのか?

  1. ログインやサインアップ、パスワード更新、などの度に設定する必要がでてくる
  2. 余計なコードは少ないほうが良い

1. ログインやサインアップ、パスワード更新、などの度に設定する必要がでてくる

deviseでの登録、更新、削除後のリダイレクト先のメソッドはafter_resetting_password_path_forafter_update_path_forafter_sign_in_path_forafter_confirmation_path_forのように複数あります。
それらを全部上書きするのはやっかいでバグの温床になる可能性が高いです。
上記の各メソッドの中では適切にsigned_in_root_pathが使われるため、resource毎のroot_pathを適切に定義すると全ての状況に対応できることになります。

2. 余計なコードは少ないほうが良い

application_controllerで上書きするパターンでも漏れなく上書きすれば期待通りのアプリケーションを得ることができますが、不必要なコードは少ないほうが読むのが楽という面もあります。
config/routes.rbの設定は本来あるべき設定だと考えられるので、config/routes.rbの設定だけで済むのであればこれに越したことがないと思います。

4. では調べるとよく出てくるパターンはいつ使うべきなのか?

同じresourceの中で、なにかしらの条件によってリダイレクト先を分ける場合には、after_xxx_path_forが便利だと思います。
例えば、権限、ステータスなどによって、遷移先が違う場合などです。

5. まとめ

deviseのリダイレクト先の設定方法について自分なりの考えを記載してみましたがいかがでしょうか?
適切にroot_pathを定義するとシンプルで少ないコードで意図した機能を実現できると思います。
改めてdeviseはよくできているなと思いました。
では良いdeviseライフを!!

stmon19

遊びが一番 人生遊び 好きにまみれてます