やりたいこと
メソッド間で認証情報を受け渡ししたい。
pass_authenticationメソッドで作った認証情報をconvertメソッドに渡したい。
問題

pass_authenticationメソッドの中でredirect toで遷移させているのに遷移されない。
ページを移動せずにそのまま次のconvertメソッドが実行され、そこでエラーになっている。
認証ページに遷移して認証情報が取得できていないのでエラーになっている。
def index
pass_authentication
convert(@drive)
end
def pass_authentication
if request.params['code'] == nil # 認証コードを持っていなかった場合
auth_uri = auth_client.authorization_uri.to_s
redirect_to auth_uri, allow_other_host: true
else
# 省略
end
end
解決法
def index
pass_authentication
return if performed?
convert(@drive)
end
performed?メソッドは、すでにredirect toやrenderが呼び出されたかどうかを返す。
perfomed?メソッドは、すでにそのアクション内でrenderかredirectがされたかを確認するメソッドです
現場から学ぶ、RailsのControllerアンチパターン
今回はpass_authenticationメソッドの中でredirect toを呼び出しているので、trueを返し、そこで処理が終了し、convertメソッドは実行されない。
convertメソッドを実行しないので、pass_authenticationメソッドにとどまったままになり、時間をかけてでもredirect toが実行されるまで待つことになる。
なぜperformed?を使うのか?
performed?メソッドを使わなくても以下のように実行されるのではないかと思った。
-
pass_authenticationメソッドが呼び出される -
redirect toが実行される - ページが遷移する
- 認証が行われて元のページに戻る
-
convertメソッドが実行される
ChatGPTに聞いたところ、2のところでredirect toと書いたから(メソッドを呼び出したから)と言ってすぐに実行されるわけではなく、続けてその次の処理が行われることもあるという。
なぜかというと、redirect toメソッドは処理を中断するものではないから。明示的に中断する処理を書かないと続く。
また、redirect toが実行されたあとでまた別のredirect toを実行しようとすると、AbstractController::DoubleRenderErrorというエラーになるらしい。
今回の場合でいうと、2で認証ページに遷移させたあと、認証ページから戻ってくることになっているから、2回リダイレクトしていることになるのかも。
というわけで、まとめると以下2つが理由だ。
- 確実に次の処理が行われないようにするため
- 二重リダイレクトエラーを防ぐため
ドキュメント

