パスワードリマインダー(忘れ)機能で、メールのURLのtokenの期限切れや不正な(存在しない)場合に、パスワード再設定ページが表示され、いざ変更しようとすると、token不正と怒られるのが不親切なので、メールのURLを開いた時に不正を知らせるように変更しました。
先ずはSpec
spec/requests/users/passwords_spec.rb を作成
require 'rails_helper' RSpec.describe 'Users::Passwords', type: :request do shared_context '期限内のtoken作成' do before do @token = Faker::Internet.password user = FactoryBot.build(:user) user.reset_password_token = Devise.token_generator.digest(self, :reset_password_token, @token) user.reset_password_sent_at = Time.now user.save! end end shared_context '期限切れのtoken作成' do before do @token = Faker::Internet.password user = FactoryBot.build(:user) user.reset_password_token = Devise.token_generator.digest(self, :reset_password_token, @token) user.reset_password_sent_at = '0000-01-01' user.save! end end # GET /users/password/edit パスワード再設定 describe 'GET /users/password/edit' do context '期限内のtoken' do include_context '期限内のtoken作成' it 'renders a successful response' do get "#{edit_user_password_path}?reset_password_token=#{@token}" expect(response).to be_successful end end context '期限切れのtoken' do include_context '期限切れのtoken作成' it 'パスワード再設定メール送信にリダイレクト' do get "#{edit_user_password_path}?reset_password_token=#{@token}" expect(response).to redirect_to(new_user_password_path) end end context '存在しないtoken' do it 'パスワード再設定メール送信にリダイレクト' do get "#{edit_user_password_path}?reset_password_token=not" expect(response).to redirect_to(new_user_password_path) end end end # PUT /users/password パスワード再設定(処理) describe 'PUT /users/password' do context '期限内のtoken' do include_context '期限内のtoken作成' it 'renders a successful response' do put user_password_path, params: { user: { reset_password_token: @token } } expect(response).to be_successful end end context '期限切れのtoken' do include_context '期限切れのtoken作成' it 'パスワード再設定メール送信にリダイレクト' do put user_password_path, params: { user: { reset_password_token: @token } } expect(response).to redirect_to(new_user_password_path) end end context '存在しないtoken' do it 'パスワード再設定メール送信にリダイレクト' do put user_password_path, params: { user: { reset_password_token: 'not' } } expect(response).to redirect_to(new_user_password_path) end end end end
確認
$ rspec spec/requests/users/passwords_spec.rb 6 examples, 4 failure
Spec通るように実装
app/controllers/users/passwords_controller.rb を変更
# GET /users/password/edit パスワード再設定 def edit return redirect_to new_user_password_path, alert: invalid_token_message unless valid_token?(params[:reset_password_token]) super end # PUT /users/password パスワード再設定(処理) def update return redirect_to new_user_password_path, alert: invalid_token_message unless valid_token?(resource_params[:reset_password_token]) super end private # 有効なtokenかを返却 # @return true: 有効期限内, false: 存在しないか、期限切れ def valid_token?(token) reset_password_token = Devise.token_generator.digest(self, :reset_password_token, token) resource = resource_class.find_by(reset_password_token: reset_password_token) resource.present? && resource.reset_password_period_valid? end # tokenエラーメッセージを返却 def invalid_token_message t('activerecord.errors.models.user.attributes.reset_password_token.invalid') end
確認
$ rspec spec/requests/users/passwords_spec.rb 6 examples, 4 failure
$ rails s -> http://localhost:3000/users/password/edit?reset_password_token=not
【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/370657dd0ab22e0842412252b5dc75199fb12fec