Ruby on RailsのDevise gemを使ってエラーCouldn't find User with 'id'=sign_inが出た時の対処法


発生したエラー内容

ユーザー登録やログイン認証のために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は以下のように記述されているかと思います。

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をdevise for :usersの後ろに移動することで解決します。

routes.rb
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