#発生したエラー内容
ユーザー登録やログイン認証のためにDevise gemを入れて、さらに自分でUser Controllerを作ったら、以下のエラーメッセージが出て、deviseのログイン画面やユーザー登録画面が動かなくなる、ユーザー情報画面が表示されないといったエラーが発生しました。
- ActiveRecord::RecordNotFound in UsersController#show
- Couldn't find User with 'id'=sign_in(sign_up)
###問題が発生した実行環境
実行環境による差分があるとは思いませんが、念のため当方の実行環境を載せておきます。
- Cloud9(Ubuntu)
- ruby 2.6.3
- Rails 6.0.3.2
- Devise 4.7.2
#問題の原因
この問題が発生したのは、user/:idというルーティングが、user/sign_inやuser/sign_upを包括してしまっていたためでした。Railsのルーティングは上から順に読み込んでいき、合致するルーティングを探しているため、resources :users が先に読み込まれて、sign_inやsign_upをidだと認識してしまったことが原因だったようです。
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
new_user_session GET /users/login(.:format) users/sessions#new
user_session POST /users/login(.:format) users/sessions#create
destroy_user_session DELETE /users/logout(.:format) users/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) users/registrations#cancel
new_user_registration GET /users/signup(.:format) users/registrations#new
edit_user_registration GET /users/edit(.:format) users/registrations#edit
user_registration PATCH /users(.:format) users/registrations#update
PUT /users(.:format) users/registrations#update
DELETE /users(.:format) users/registrations#destroy
POST /users(.:format) users/registrations#create
上のようにuser GET /users/:id(.:format) users#show がDevise Gemのルーティングより上に来てしまっている場合、routes.rbは以下のように記述されているかと思います。
Rails.application.routes.draw do
resources :users, only: [:index, :show]
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'},
path_names: {
sign_in: 'login',
sign_out: 'logout',
sign_up: 'signup'
}
end
#解決策
routes.rbの書き方を修正します。具体的には、resources :users, only: [:index, :show](か get "user/:id" ,to: "user#show")をdevise for :usersの後ろに移動することで解決します。
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'},
path_names: {
sign_in: 'login',
sign_out: 'logout',
sign_up: 'signup'
}
resources :users, only: [:index, :show]
end
正しい順番で記載してからrails routesで確認してみると、user GET /users/:id(.:format) users#showよりもDevise gemのルーティングが上に来ていることが確認できるかと思われます(上記コードではpath_namesを使ってsign_inをloginに、sign_outをlogoutに変更していますが、大意に影響はありません)。
new_user_session GET /users/login(.:format) users/sessions#new
user_session POST /users/login(.:format) users/sessions#create
destroy_user_session DELETE /users/logout(.:format) users/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) users/registrations#cancel
new_user_registration GET /users/signup(.:format) users/registrations#new
edit_user_registration GET /users/edit(.:format) users/registrations#edit
user_registration PATCH /users(.:format) users/registrations#update
PUT /users(.:format) users/registrations#update
DELETE /users(.:format) users/registrations#destroy
POST /users(.:format) users/registrations#create
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
この方法に直したら問題なくログインできるようになりました。
#補足:devise_forメソッドで生成されるルーティングを整理してみました
devise_forメソッドを使ったルーティングがわかりづらかったので、resources :usersで生成されるルーティングとの対応表を作りました。合わせてご査収ください。
resource :users | devise_for |
---|---|
users#index | なし |
users#new | devise/registration#new |
users#create | devise/registration#create |
users#edit | devise/registration#edit |
users#show | なし |
users#update | devise/registration#update |
users#destroy | devise/registration#destroy |