先に結論
devise-i18n-views
の影響で、ユーザーのパスワード変更が出来なかった。
READMEにもかいてあるが、このgemはdevise-i18nにマージされたのでこっちを使うようにする。
環境
- rails 5.2.3
- devise 4.6.2
- devise-i18n 1.8.0
- devise-i18n-views 今回これが要らなかった話
何が起こった
deviseで管理しているモデルのパスワード変更をしようとしたらトークンが不正だと言われる。
- ログイン画面から「パスワードを忘れた」をクリック
- 登録されているメールアドレスを入力して送信
- 確認メール内のリンクをクリック
- パスワード再設定のフォームが開くので、新しいパスワードを入力
- reset_password_tokenが不正だと言われる orz
調査
「rails devise reset_password_by_token invalid」とかでググってみると、この手の話題は幾つか見つかった。
このissueとか参考になった。
具体的に、deviseはreset_password_tokenを作成するときに、以下のようなコードになっていた。
def set_reset_password_token
raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
self.reset_password_token = enc
self.reset_password_sent_at = Time.now.utc
save(validate: false)
raw
end
https://github.com/plataformatec/devise/blob/master/lib/devise/models/recoverable.rb#L89
で、この戻り値 raw
を受け取ってパスワードリセットメールを送信している
def send_reset_password_instructions
token = set_reset_password_token
send_reset_password_instructions_notification(token)
token
end
この処理を見ると、実際はDBに保存されている reset_password_token
の値とパスワードリセットのメールに記載されているreset_password_token
は違うものだった
localhost:3000/users/password/edit?reset_password_token=vu9utDw1Mri848sEqPYf
←これ
issueにも書いてある通り、このリンクが書いてあるのはviewのmailer配下なので、問題があるとすればここだと思った。
が、今回はdeviseのファイルを翻訳するために
- devise-i18n
- devise-i18n-views
というgemを入れていた。
devise-i18n-views
のソースコードを調べたところ、 ここが原因となっていた。
(Devise::VERSION.start_with?('3.') ? @token : @resource.reset_password_token)
deviseは4.6.2なのでfalseが実行されていた。。。
対応
- Gemfileから
devise-i18n-views
を削除 - bundle update
- bundle clean