⭐️パスワードリセットとは?
└パスワードを変更したい場合に、任意で変更することができるツールのこと。
Rails上で実装するためには以下の手順で実装していく!
==============================
①:localhost3000にて「パスワードを忘れた方」をクリックすると「パスワードリセット申請」画面へ推移するようにする。
②:現在のメールアドレスを入力すれば、メールアドレス宛に「パスワード再発行メール」が届くようにする。
③:パスワード再発行メール(letter-opener)のリンクをクリックすると、パスワードリセット用リンクに飛ぶようにする。
④:パスワードリセット用の画面にて新しいパスワードを設定後に、ログイン画面へ遷移するようにする。
⑤:新しいパスワードにてログインできる状態にする。
==============================
実際の手順:
・$ rails g sorcery:install reset_password --only-submodules でsorceryのReset passwordモジュールをインストールする。
└Reset passwordモジュールをインストールすることで、rails上で使えるようになる。
[ターミナル上]
rails g sorcery:install reset_password --only-submodules
[以下ファイルが生成される]
Running via Spring preloader in process 71125
gsub config/initializers/sorcery.rb
insert app/models/user.rb
create db/migrate/20211009040003_sorcery_reset_password.rb
class SorceryResetPassword < ActiveRecord::Migration[5.2]
def change
add_column :users, :reset_password_token, :string, default: nil
add_column :users, :reset_password_token_expires_at, :datetime, default: nil
add_column :users, :reset_password_email_sent_at, :datetime, default: nil
add_column :users, :access_count_to_reset_password_page, :integer, default: 0
add_index :users, :reset_password_token, **unique: true (追加する)**
end
end
パスワードリセット用のメイラーを作成する
└メイラーとは?(参考文献:https://note.com/izuha0/n/nd7f94d730527)
Railsで,メールを送るときには.Action Mailerという仕組みのこと。
メイラーはテンプレートを通じてメールの作成・送信を実行します。
$ rails g mailer UserMailer reset_password_email
[ターミナル上]
rails g mailer UserMailer reset_password_email
[以下ファイルが生成される]
Running via Spring preloader in process 71280
create **app/mailers/user_mailer.rb**
invoke erb
create ****app/views/user_mailer
create **app/views/user_mailer/reset_password_email.text.erb**
create **app/views/user_mailer/reset_password_email.html.erb**
└**/mailers/user_mailer.rb** が生成されており、user_mailer の下に2つのビューファイルが生成されていますね。
こちらは実際にユーザに対して送るメールの中身となるファイルです。テキスト形式とHTML形式になります。
ユーザによってはHTML形式のメールを受け取りたくない人もいるので、テキストメールも作成しておきます。
メリラービューの作成:
app/views/user_mailer/reset_password_email.text.erb
<%= @user.decorate.full_name %>様
===========================================
パスワード再発行のご依頼を受け付けました。
こちらのリンクからパスワードの再発行を行ってください。
<%= @url %>
app/views/user_mailer/reset_password_email.html.erb
<%= @user.decorate.full_name %>様
<p>パスワード再発行のご依頼を受け付けました。</p>
<p>以下のリンクからパスワードの再発行を行ってください。</p>
<p><a href="<%= @url %>"><%= @url %></a></p>
上記の@urlの中身は、token(トークン)で発行された再登録用のurlが入っています。
トークンとは?の参考文献:https://qiita.com/dawn_628/items/5842bdbf92510637bca2
作成したメールを送信するためのメソッドを記述する:
app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
default from: '[email protected]'
def reset_password_email@user = User.find(user.id)
@url = edit_password_reset_url(@user.reset_password_token)
mail(to: user.email, subject: 'パスワードリセット')
end
end
└①default from: '[email protected]'でメールの送信元のアドレスを指定できる。
②mail(to: user.email,subject: 'パスワードリセット')でメールの宛先、件名を指定できる。
※こちらの@user、@url はどこで使われているのかというと、先ほど作成したメイラービューの中で使われている!
パスワードリセットを処理するコントローラを作成する。
$ rails g controller PasswordResets new create edit update
[ターミナル上]
rails g controller PasswordResets new create edit update
[以下ファイルが作成される]
Running via Spring preloader in process 71542
create app/controllers/password_resets_controller.rb
invoke erb
create app/views/password_resets
create app/views/password_resets/new.html.erb
create app/views/password_resets/create.html.erb
create app/views/password_resets/edit.html.erb
create app/views/password_resets/update.html.erb
invoke decorator
create app/decorators/password_reset_decorator.rb
app/controllers/password_resets_controller.rb
class PasswordResetsController < ApplicationController
# Rails 5以降では、次の場合にエラーが発生します。
# before_action :require_login
# ApplicationControllerで宣言されていません。
skip_before_action :require_login
# パスワードリセット申請画面へレンダリングするアクション
def new; end
# パスワードのリセットを要求するアクション。
# ユーザーがパスワードのリセットフォームにメールアドレスを入力して送信すると、このアクションが実行される。
def create
@user = User.find_by(email: params[:email])
#@user = User.find_by(email: params[:email])でユーザーが見つからなかったときは@userにはnilが入ります。
そのnilに対してdeliver_reset_password_instructions!メソッドを実行すると、UndefinedMethodの例外が発生します。
そこで&.を使用すれば、もしnilであってもnilを返すだけになり、例外は発生しません。
# この行は、パスワード(ランダムトークンを含むURL)をリセットする方法を説明した電子メールをユーザーに送信します
@user&.deliver_reset_password_instructions!
#@user&.deliver_reset_password_instructions! ですが、&.はメソッドの実行対象のオブジェクトがnil(ユーザーがいなかったとき)だった場合を考慮した記法です。
# 上記は@user.deliver_reset_password_instructions! if @user と同じ
# 電子メールが見つかったかどうかに関係なく、ユーザーの指示が送信されたことをユーザーに伝えます。
# これは、システムに存在する電子メールに関する情報を攻撃者に漏らさないためです。
redirect_to login_path, success: t('.success')
end
# パスワードのリセットフォーム画面へ遷移するアクション
def edit
@token = params[:id]
@user = User.load_from_reset_password_token(params[:id])
return not_authenticated if @user.blank?
end
# ユーザーがパスワードのリセットフォームを送信したときに発生
def update
@token = params[:id]
@user = User.load_from_reset_password_token(params[:id])
return not_authenticated if @user.blank?
#User.load_from_reset_password_token(params[:id])にて、有効期限切れなどでユーザーが取得できなかったとき、not_authenticatedとなります。
# 次の行は、パスワード確認の検証を機能させます
@user.password_confirmation = params[:user][:password_confirmation]
# 次の行は一時トークンをクリアし、パスワードを更新します
if @user.change_password(params[:user][:password])
redirect_to login_path, success: t('.success')
else
flash.now[:danger] = t('.fail')
render :edit
end
end
end
PasswordResetsコントローラのルーティングを設定
[routes.rb]
resources :password_resets, only: %i[new create edit update]
userモデルにバリデーションを追記する。
[user.rb]
validates :reset_password_token, presence: true, uniqueness: true, allow_nil: true
└tokenは一意なものでなければいけませんので、uniqueness: true を付与します。
しかし、パスワードを変更した際、reset_password_token はnilになるのでユニーク制約に引っかかってしまいます。nilを許可する必要があるでしょう。
そこでallow_nil オプションを使います。allow_nil: true を付与することで、対象の値がnilの場合にバリデーションをスキップします。
ビューファイルを作成する
パスワード申請画面
app/views/password_resets/new.html.erb
<%= content_for(:title, t('.title')) %>
<div class="container">
<divclass="row">
<divclass="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
<h1><%= t '.title' %></h1>
<!--こちらのform_with はモデルと紐付いていない点に注意しましょう。また、そのことよりラベルが日本語化しませんので、自分で日本語化する記述を追加しましょう。-->
<%= form_with url: password_resets_path, local: true do |f| %>
<div class="form-group">
<%= f.label :email, User.human_attribute_name(:email) %><br />
<%= f.email_field :email,class: 'form-control' %>
</div>
<%= f.submit t('password_resets.new.submit'),class: 'btn btn-primary' %>
<% end %>
</div>
</div>
</div>
パスワードリセット画面
app/views/password_resets/edit.html.erb
<%= content_for(:title, t('.title')) %>
<div class="container">
<divclass="row">
<divclass="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
<h1><%= t '.title' %></h1>
<%= form_with model: @user, url: password_reset_path(@token), local: true do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<divclass="form-group">
<%= f.label :email %>
<%= @user.email %>
</div>
<divclass="form-group">
<%= f.label :password %>
<%= f.password_field :password,class: 'form-control' %>
</div>
<divclass="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation,class: 'form-control' %>
</div>
<divclass="actions">
<pclass="text-center">
<%= f.submitclass: 'btn btn-primary' %>
</p>
</div>
<% end %>
</div>
</div>
</div>
パスワードリセット申請リンクの表示する
app/views/user_sessions/new.html.erb
[〜〜一部省略〜〜]
<% end %>
<div class='text-center'>
<%= link_to (t '.to_register_page'), new_user_path %>
<%= link_to t('.password_forget'), new_password_reset_path %>
<!--ログイン画面にパスワードリセット申請画面へのリンクを追加しましょう。-->
</div>
</div>
</div>
gemfileにletter_opener_webを追加する
[gemfile]
group :development do
gem 'letter_opener_web', '~> 1.0'
end
└入力後、bundle installする!
ルーティングにLetterOpenerWebにアクセスするために必要な記述を追記する
[routes.rb]
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
[config/enviroments/developments]
config.action_mailer.delivery_method = :letter_opener_web
config.action_mailer.default_url_options = { host: 'localhost:3000' }
メールが送られてきているか確認する
こちらのURLにアクセスしてメールが送られてきているか確認してみましょう。
configを導入する
configとは?
└Configは環境固有の設定を簡単で使いやすい方法で管理できるようになるgemです。
host情報はconfigというgemを使ってsettings/development.ymlに記載する。
まずGemfile に追記しましょう。
[Gemfile]
gem 'config'
└入力後、bundle install
configを導入したら下記を入力する。
[ターミナル上]
rails g config:install
[下記ファイルが作成される]
Running via Spring preloader in process 78325
create config/initializers/config.rb
create config/settings.yml
create config/settings.local.yml
create config/settings
create config/settings/development.yml
create config/settings/production.yml
create config/settings/test.yml
append .gitignore
これにより、カスタマイズ可能な構成ファイルconfig/initializers/config.rbと一連のデフォルト設定ファイルが生成されます。
| config/initializers/config.rb | configの設定ファイル |
|---|---|
| config/settings.yml | すべての環境で利用する定数を定義 |
| config/settings.local.yml | ローカル環境のみで利用する定数を定義 |
| config/settings/development.yml | 開発環境のみで利用する定数を定義 |
| config/settings/production.yml | 本番環境のみで利用する定数を定義 |
| config/settings/test.yml | テスト環境のみで利用する定数を定義 |
host情報をsettings/development.ymlに記載する
[config/setting/development.yml]
default_url_options:
host: 'localhost:3000'
[config/enviroments/development.rb]
config.action_mailer.perform_caching = false
config.action_mailer.default_url_options = Settings.default_url_options.to_h
config.action_mailer.delivery_method = :letter_opener_web
※本番環境では以下のようにします。host: 'example.com'の部分には自分のドメインを設定します。
[config/setting/production.yml]
default_url_options:
protcol: 'https'
host: 'example.com'
[config/enviroments/production.rb]
config.action_mailer.default_url_options = Settings.default_url_options.to_h
runteq yutube:https://www.youtube.com/watch?v=9Fccs5JegdE