パスワードの再設定 | rails チュートリアル 18
Ruby on Rails チュートリアル:実例を使って Rails を学ぼうの第12章 パスワードの再設定の勉強メモです。
ここでは、パスワードを忘れた時のパスワードの再設定ができるようにする。
PasswordResetsリソース
Pw再設定用コントローラーを作成する。
$ bundle exec rails generate controller PasswordResets new edit --no-test-framework
「–no-test-framework」で、テストを生成しないというオプションを指定している
次に、routeを修正
Rails.application.routes.draw do get 'password_resets/new' get 'password_resets/edit' root 'static_pages#home' get '/help', to: 'static_pages#help' get '/about', to: 'static_pages#about' get '/contact', to: 'static_pages#contact' get '/signup', to: 'users#new' post '/signup', to: 'users#create' get '/login', to: 'sessions#new' post '/login', to: 'sessions#create' delete '/logout', to: 'sessions#destroy' resources :users patch '/users/:id/edit', to: 'users#update' resources :account_activations, only: [:edit] resources :password_resets, only: [:new, :create, :edit, :update] end
続いて、パスワード再設定画面へのリンクを追加する。
<p><%= link_to "forgot password", new_password_reset_path %> / <%= link_to "Sign up now!", signup_path %></p>
Userモデルに属性を追加する。
reset_digest属性とreset_sent_at属性をUserモデルに追加する。
$ bundle exec rails generate migration add_reset_to_users reset_digest:string reset_sent_at:datetime $ bundle exec rails db:migrate
新しいパスワード再設定画面ビューを作成
$ touch app/views/password_resets/new.html.erb
<% provide(:title, "Forgot password") %> <div class="container"> <div class="ta_center"> <br> <br> <br> <h1 class="title_signup">Forgot password</h1> <p>登録済みのメールアドレスを入力してください</p> <%= form_with(scope: :password_reset, url: password_resets_path, html: {class: ''}, local: true) do |f| %> <table class="mr_auto ml_auto"> <tr> <th><%= f.label :email %></th> <td><%= f.email_field :email, class: 'form-control' %></td> </tr> </table> <%= f.submit "Submit", class: "btn btn-primary" %> <% end %> <br> <br> <br> </div> </div>
その後、password_resets_controller.rbを修正、createアクションを追加する。
class PasswordResetsController < ApplicationController def new end def create @user = User.find_by(email: params[:password_reset][:email].downcase) if @user @user.create_reset_digest @user.send_password_reset_email flash[:info] = "登録されているされているメールアドレスにパスワードリセット用のメールをお送りしました。" redirect_to root_url else flash.now[:danger] = "このメールアドレスは登録されていません" render 'new' end end def edit end end
つぎに、Userモデルにパスワード再設定用メソッドを追加する
class User < ApplicationRecord attr_accessor :remember_token, :activation_token, :reset_token . . . # パスワード再設定の属性を設定する def create_reset_digest self.reset_token = User.new_token update_attribute(:reset_digest, User.digest(reset_token)) update_attribute(:reset_sent_at, Time.zone.now) end # パスワード再設定のメールを送信する def send_password_reset_email UserMailer.password_reset(self).deliver_now end private . . . end
これで、登録されていないアドレスに対してのエラーメッセージが表示できるようになった。
パスワード再設定のメール送信
パスワード再設定のリンクをメール送信できるように、mailerを修正する。
class UserMailer < ApplicationMailer def account_activation(user) @user = user mail to: user.email, subject: "Account activation" end def password_reset(user) @user = user mail to: user.email, subject: "Password reset" end end
つづいて、メール用のテキストとhtmlのviewを修正
To reset your password click the link below: <%= edit_password_reset_url(@user.reset_token, email: @user.email) %> This link will expire in two hours. If you did not request your password to be reset, please ignore this email and your password will stay as it is.
<h1>Password reset</h1> <p>To reset your password click the link below:</p> <%= link_to "Reset password", edit_password_reset_url(@user.reset_token, email: @user.email) %> <p>This link will expire in two hours.</p> <p> If you did not request your password to be reset, please ignore this email and your password will stay as it is. </p>
最後に、パスワード再設定のプレビューメソッドを修正
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer class UserMailerPreview < ActionMailer::Preview # Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation def account_activation user = User.first user.activation_token = User.new_token UserMailer.account_activation(user) end # Preview this email at # http://localhost:3000/rails/mailers/user_mailer/password_reset def password_reset user = User.first user.reset_token = User.new_token UserMailer.password_reset(user) end end
これで、登録されているアドレスを入力しても、エラーにならないようになった。
パスワードを再設定する
パスワード再設定のフォーム用のviewを修正
<% provide(:title, 'Reset password') %> <div class="container"> <div class="ta_center"> <br> <br> <br> <h1 class="title_signup">Forgot password</h1> <p>新しいパスワードを入力してください。</p> <%= form_with(model: @user, url: password_reset_path(params[:id]), html: {class: ''}, local: true) do |f| %> <%= render '/users/error_messages', user: @user %> <%= hidden_field_tag :email, @user.email %> <table class="mr_auto ml_auto"> <tr> <th><%= f.label :password %></th> <td><%= f.password_field :password, class: 'form-control' %></td> </tr> <tr> <th><%= f.label :password_confirmation, "Confirmation" %></th> <td><%= f.password_field :password_confirmation, class: 'form-control' %></td> </tr> </table> <%= f.submit "Update password", class: "btn btn-primary" %> <% end %> <br> <br> <br> </div> </div>
コントローラーも合わせて修正
class PasswordResetsController < ApplicationController before_action :get_user, only: [:edit, :update] before_action :valid_user, only: [:edit, :update] before_action :check_expiration, only: [:edit, :update] def new end def create @user = User.find_by(email: params[:password_reset][:email].downcase) if @user @user.create_reset_digest @user.send_password_reset_email flash[:info] = "登録されているされているメールアドレスにパスワードリセット用のメールをお送りしました。" redirect_to root_url else flash.now[:danger] = "このメールアドレスは登録されていません" render 'new' end end def edit end def update if params[:user][:password].empty? @user.errors.add(:password, :blank) render 'edit' elsif @user.update_attributes(user_params) log_in @user @user.update_attribute(:reset_digest, nil) flash[:success] = "パスワードがリセットされました。" redirect_to @user else render 'edit' end end private def user_params params.require(:user).permit(:password, :password_confirmation) end def get_user @user = User.find_by(email: params[:email]) end # 正しいユーザーかどうか確認する def valid_user unless (@user && @user.activated? && @user.authenticated?(:reset, params[:id])) redirect_to root_url end end # トークンが期限切れかどうか確認する def check_expiration if @user.password_reset_expired? flash[:danger] = "Password reset has expired." redirect_to new_password_reset_url end end end
メモ
うーん、(´ε`;)ウーン…
heroku環境だとうまくいくけど、ローカルだとうまくいかない。。
valid_userメソッドが、うまく動いていない。。
どうやら、valid_userメソッドはうまく動いていた。
うまくいかないと思い込んでいたのは、「http://localhost:3000/rails/mailers/user_mailer/password_reset」で生成されているリンクがうまく動いていないかもと思っていたこと。しかし、正しいローカルのリンクは、rails sでlogに表示されている文字列だった。
コメント
同じカテゴリの前後の記事
TRASHの最新記事
- KATOON.NET
- TRASH
- パスワードの再設定 | rails チュートリアル 18