結論
以下、5パターン。上から順に優先度が高い。
usersというモデルにdeviseをマッピングさせた場合、
- ログイン前にアクセスしようとしたページ
- user_root_path(as: user_root_pathを指定したパターン)
- user_root_path(名前空間 + rootで設定したパターン)
- root_path(deviseマッピングとは関係ないroot_path)
- "/"
詳細(サインインの観点から)
「サインイン後のリダイレクト先を設定したい!!」
となると、after_sign_in_path_forメソッドを使いますが、
きちんと理解しておかないと、「なんかうまくいかないな」という状態になりがちです。
しっかりやっていきましょう。
下記は、after_sign_in_path_forのソースです。
Git_Hub:after_sign_in_path_forメソッド
def after_sign_in_path_for(resource_or_scope)
stored_location_for(resource_or_scope) || signed_in_root_path(resource_or_scope)
end
さすが有名gemです。メソッド名でなんとなくわかりますね!!
-
stored_location_for(resource_or_scope)
未ログイン時にアクセスしようとしたページがあった場合、サインインした後に飛ばす。 -
signed_in_root_path(resource_or_scope)
いきなりログインページにアクセスした場合は、このメソッドの戻り値の場所に飛ばす。
ログイン後のリダイレクト先の理解には、
**signed_in_root_path(resource_or_scope)**メソッド
の理解がキーになりそうです。
早速見てみましょう。
def signed_in_root_path(resource_or_scope)
# モデルオブジェクトが渡されると、deviseでマッピングされたスコープ(usersとか)を返す。
# もしdeviseでマッピングしているモデルがadminという名前空間に属している場合、:admin_usersになる。
scope = Devise::Mapping.find_scope!(resource_or_scope)
# deviseを使うモデルが複数ある場合、mappings(ハッシュ)のうち[scope]を取得し、そのrouter_nameを代入する。
# router_nameは、Devise::Mappingに対してoptionが渡されないとnilになるから基本nilっぽい。
router_name = Devise.mappings[scope].router_name
home_path = "#{scope}_root_path"
# router_nameは基本nilっぽいので、実行されない。selfはobjectクラスのmain。
context = router_name ? send(router_name) : self
# contextに対してhome_pathを呼べるなら実行。trueはhome_pathがプライベートメソッドでも呼ぶよの意味。
if context.respond_to?(home_path, true)
context.send(home_path)
# contextに対して、root_pathを呼べるなら実行。
elsif context.respond_to?(:root_path)
context.root_path
# ただのroot_pathが呼べるなら実行。
elsif respond_to?(:root_path)
root_path
# トップページにリダイレクト
else
"/"
end
end
ふむふむ。
-
context.respond_to?(home_path, true)
-
context.respond_to?(:root_path)
の違いだけちょっとあいまいだが、 -
admin/users#indexとかの名前空間(admin)があるパターンは、
context.respond_to?(home_path, true)で実行される -
名前空間(admin)がないパターン(usersのみ)は
context.respond_to?(:root_path)で実行される
と理解した。
home_path = "#{scope}_root_path"
の#{scope}は、
adminとかの名前空間 + deviseでマッピングしているモデル名となる。
最終的にuser_root_pathとなるのは同じだが、内部的には意味が違うのではないだろうか。。。
下記は、user_root_pathで、home_pathと合致する。
devieでマッピングされたモデルに対して、home_pathはあるか?と聞いている。
context.respond_to?(home_path, true)
get to: "users#index", as: user_root_path
下記は、user_root_pathだが、home_pathとは合致しない。
deviseでマッピングされたモデルに対して、root_pathはあるか?と聞いている。
context.respond_to?(:root_path)
namespace users do
root to: "users#index"
end
認識違いあれば、ご指摘ください!!