Rails + Devise 環境でのフレンドリーフォワーディング機能を修正

Rails の Devise でログイン後にログインする直前のページにリダイレクトさせる | EasyRamble で書いていた、Devise 利用時のフレンドリーフォワーディング機能の実装コードにバグがありましたので修正しました。

— 環境 —
Rails 5.0.0.1
Devise 4.2

【追記 2016/11/08】
Rails 5 + Devise 4.2 の最新バージョンで実装して動作確認を行いましたところ、正常に動作することを確認いたしました。
【追記ここまで】

— 記事初回公開時の環境 —
Rails 4.0.1
Devise 3.2.2

スポンサーリンク

Devise でのパスワードリセット機能

Devise で Recoverable モジュールを有効にすると、パスワードリセット機能が使えます。Devise の Recoverable モジュールでパスワードリセットする場合、ウェブページの操作は以下の流れとなる。

1. ユーザーがログイン画面でパスワードを忘れましたか?をクリックして /users/password/new にアクセス。
2. フォームにメアドを入力して、パスワードリセット要求のメールを送信する。
3. メール中のリセットパスワードトークンを含むURLをクリックして、/users/password/edit?reset_password_token=***** にアクセス。
4. フォームに新しいパスワードを入力して送信して、新しいパスワードに更新する。

以上の流れになりますが、この 4 の後のリダイレクト部分でエラー発生。ブラウザで「ページの自動転送設定が正しくありません。このアドレスへのリクエストに対するサーバの自動転送設定がループしています。」というリダイレクトエラー時に見るエラーが発生しました。

ApplicationController#store_location を修正

Devise::PasswordsController と Recoverable モジュールのソースを読んで修正したのですが、結論を言うと ApplicationController に定義していた store_location メソッドを以下のように修正しました。

パスワードリセット機能を用いる時は、session[:previous_url] を保存しないようにと考えて、

と if 文に書いていたのですけど、これだと全然駄目ですね。/users/password/new や /users/password/edit?reset_password_token=***** のURLが session[:previous_url] に入ってしまいます。これがバグの原因でした。なので、この部分を以下のように修正。

/users/password/new や /users/password/edit?reset_password_token=***** など /users/password でパスが始まるURLは session[:previous_url] に保存しないようにします。

Devise::PasswordsController と Devise Recoverable Module のソース読み

Devise のソースを読んで理解した部分を、簡単にまとめておきます。

Devise::PasswordsController

new
/users/password/new
パスワードリセット用のメールアドレスを入力させるフォームを表示させるページ。

create
パスワードリセット要求メールを送信させるアクション。メール送信フォームをサブミットして成功した後に、after_sending_reset_password_instructions_path_for メソッドで指定したページにリダイレクトさせる。

How To: Redirect URL after sending reset password instructions

edit
/users/password/edit?reset_password_token=*****
メール中のリセットパスワードトークンを含むURLをクリックした後に、新しいパスワードの入力フォームを表示させる。

update
新しいパスワードの入力フォームがサブミットされた時に、パスワードを更新するアクション。成功したら after_resetting_password_path_for で指定してページにリダイレクト。この after_resetting_password_path_for の中身は、after_sign_in_path_for を呼んでいるだけ。

ということで、フレンドリーフォワーディング機能を作った際にオーバーライドした after_sign_in_path_for でミスったな…と見当がつきました。

Devise Recoverable Module

send_reset_password_instructions, reset_password_by_token など Devise::PasswordsController で使われるメソッドが定義されている。

以上ですが、Devise に関してはかなり慣れてきたので、何か問題が起こったらソースを読めば大体解決できる感触があります。慣れた gem に関しては、下手にググるより公式ドキュメントとソース読んだほうが速い感じですね。

最後ちなみに gem のソース読む時は、bundler で入れているのであれば…

ってやると楽です。

スポンサーリンク
パーフェクト Ruby on Rails は、最近読んだ Rails 本の中では一番役に立った本です。Chef や Capistrano など Rails と共によく使用される技術にも触れてあります。Ruby on Rails 4 アプリケーションプログラミングは、入門的な内容で Rails の機能全体を網羅されています。
スポンサーリンク
 
Twitterを使っていますのでフォローお願いたします!ブログの更新情報もつぶやいてます^^
(英語学習用)

Leave Your Message!