Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
28
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@miyazaki_yusuke

「localhost でリダイレクトが繰り返し行われました。」はルーティングのせいだった、Ruby on Rails エラーの分析

謎のエラーに苦しめられました。
結論から言うと原因は「routes.rb」への記載の順番でした。

個人ブログに同様の内容を書いておりましたが、技術的な内容はQiitaに集約することにしたので、こちらにも投稿します。
(参考)個人ブログ

※ バージョンは、Ruby:2.3.0、Rails:5.1.4です。

事象

本件に関係のある箇所を抜粋しています。

routes.rb
  resources :users, only: [:show]
  devise_for :users, controllers: { :omniauth_callbacks => "omniauth_callbacks", registrations: 'registrations'}

devise gemを利用してログイン機能を実装しています。
ユーザー詳細ページをつけるために、resources :users, only: [:show] で users#show のためのルーティングを設定しています。

users_controller.rb
  before_action :sign_in_required, only: [:show]
  def show
  # 以下略
application_controller.rb
  private
    def sign_in_required
      redirect_to new_user_session_url unless user_signed_in?
    end

発生したエラー
スクリーンショット 2018-03-30 22.13.24.png
(言われた通り大人しくCookieを消しましたが効果ありませんでした)

ログ

Started GET "/users/sign_in" for 127.0.0.1 at 2018-02-19 21:58:38 +0900
Processing by UsersController#show as HTML
  Parameters: {"id"=>"sign_in"}
Redirected to http://localhost:3000/users/sign_in
Filter chain halted as :sign_in_required rendered or redirected
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

Started GET "/users/sign_in" for 127.0.0.1 at 2018-02-19 21:58:38 +0900
Processing by UsersController#show as HTML
  Parameters: {"id"=>"sign_in"}
Redirected to http://localhost:3000/users/sign_in
Filter chain halted as :sign_in_required rendered or redirected
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

これの無限ループ

解決法

routes.rb
  devise_for :users, controllers: { :omniauth_callbacks => "omniauth_callbacks", registrations: 'registrations'}
  resources :users, only: [:show]

順番を入れ替えただけで直りました。マジか、、

分析

エラーしている状態のrails routesのログ

                           user GET      /users/:id(.:format)                   users#show
               new_user_session GET      /users/sign_in(.:format)               devise/sessions#new
                   user_session POST     /users/sign_in(.:format)               devise/sessions#create
           destroy_user_session DELETE   /users/sign_out(.:format)              devise/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)                registrations#cancel
          new_user_registration GET      /users/sign_up(.:format)               registrations#new
         edit_user_registration GET      /users/edit(.:format)                  registrations#edit
              user_registration PATCH    /users(.:format)                       registrations#update
                                PUT      /users(.:format)                       registrations#update
                                DELETE   /users(.:format)                       registrations#destroy
                                POST     /users(.:format)                       registrations#create
user_twitter_omniauth_authorize GET|POST /users/auth/twitter(.:format)          omniauth_callbacks#passthru
 user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) omniauth_callbacks#twitter
          new_user_confirmation GET      /users/confirmation/new(.:format)      devise/confirmations#new
              user_confirmation GET      /users/confirmation(.:format)          devise/confirmations#show
                                POST     /users/confirmation(.:format)          devise/confirmations#create

エラー解決した状態のrails routesのログ

                         Prefix Verb     URI Pattern                            Controller#Action
               new_user_session GET      /users/sign_in(.:format)               devise/sessions#new
                   user_session POST     /users/sign_in(.:format)               devise/sessions#create
           destroy_user_session DELETE   /users/sign_out(.:format)              devise/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)                registrations#cancel
          new_user_registration GET      /users/sign_up(.:format)               registrations#new
         edit_user_registration GET      /users/edit(.:format)                  registrations#edit
              user_registration PATCH    /users(.:format)                       registrations#update
                                PUT      /users(.:format)                       registrations#update
                                DELETE   /users(.:format)                       registrations#destroy
                                POST     /users(.:format)                       registrations#create
user_twitter_omniauth_authorize GET|POST /users/auth/twitter(.:format)          omniauth_callbacks#passthru
 user_twitter_omniauth_callback GET|POST /users/auth/twitter/callback(.:format) omniauth_callbacks#twitter
          new_user_confirmation GET      /users/confirmation/new(.:format)      devise/confirmations#new
              user_confirmation GET      /users/confirmation(.:format)          devise/confirmations#show
                                POST     /users/confirmation(.:format)          devise/confirmations#create
                           user GET      /users/:id(.:format) 

当然、

user GET      /users/:id(.:format)     users#show

の行の場所が変わるだけです。

ログをよく見てみると、

Started GET "/users/sign_in" for 127.0.0.1 at 2018-02-19 21:58:38 +0900
Processing by UsersController#show as HTML
  Parameters: {"id"=>"sign_in"}
Redirected to http://localhost:3000/users/sign_in

GET "/users/sign_in" にアクセスしようとしてるけど、GET "/users/:id" に "id" = "sign_in" としてアクセスしちゃってる・・・
そして、 users#show はログインしていないとログインページに強制リダイレクトする設定になっているので、 GET "/users/sign_in" にアクセスして以下、無限ループです。

更に、routes.rbの記載の順番によって、エラー発生の有無が決まるのは、

Railsのルーティングは、ルーティングファイルの「上からの記載順に」マッチします。

のためでした。
(参考)Rails のルーティング | Rails ガイド

つまり、解決した時には、GET "/users/sign_in" にアクセスしようとした時に、GET "/users/:id" が一番上になかったために引っかからず、正しいルーティングを選択できたからでした。

ルーティングも奥が深いですね。
まだ知らないことばっかりで楽しいな〜(エラー最中はイライラが止まらないけど、解決して分析してスッキリするの好き)

ご指摘・ご感想等いただけますと大変嬉しいです!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
28
Help us understand the problem. What are the problem?