kouの技術的メモ

学習した内容の定着やアウトプット用に開設しました

Railsチュートリアル12章 パスワードの再設定

11章最後の起こった外部サービスが原因でメールが送れない問題ですが、無事に解決できました。
SendGrid社のフィルタリングに引っかかってしまい、アカウントが停止になってしまったようなので、

こういう場合はSendGrid社の米本社の方の文面を送ってほしいとFAQページに書いてあったので、英文で現状の報告とアカウント停止解除をお願いするメールを送りました。

数通のやり取りの後、SendGrid社のシステムを使えるようになり、無事に11章でのメールによるアカウント登録機能を完成させることができました。

無料ユーザーにもかかわらずSendGrid社のサポート担当の方の素早いご丁寧な対応に感謝いたします。


今回の12章はパスワードの再設定です。
再設定の流れとしては以下で、

ログイン画面でパスワードの再設定リンクを踏むと、メールアドレス入力フォームになり、
これにアドレスを入力すると再設定用のリンクを含んだメールが送られ、
メールのリンクを踏むと、パスワード再設定用のフォーム画面が表示され、これによってパスワードが再設定されます。

また、11章でパスワード再設定用のメイラーの基本部分は生成してあるので、これを利用します。

アルゴリズムとしては11章のアカウントメール登録機能と似たような仕組みで、メールリンクの後にパスワード再設定ファームに入力する部分がプラスになります。 以下サーバ側の処理の流れになります。

  1. ユーザーがパスワードの再設定をリクエストすると、ユーザーが送信したメールアドレスをキーにしてデータベースからユーザーを見つける

  2. 該当のメールアドレスがデータベースにある場合は、再設定用トークンとそれに対応するリセットダイジェストを生成する

  3. 再設定用ダイジェストはデータベースに保存しておき、再設定用トークンはメールアドレスと一緒に、ユーザーに送信する有効化用メールのリンクに仕込んでおく

  4. ユーザーがメールのリンクをクリックしたら、メールアドレスをキーとしてユーザーを探し、データベース内に保存しておいた再設定用ダイジェストと比較する (トークンを認証する)

  5. 認証に成功したら、パスワード変更用のフォームをユーザーに表示する

12.1.1 PasswordResetsコントローラ

11章ではメールリンクを踏むだけで本登録完了でしたので、 edit_account_activation GET /account_activations/:id/edit(.:format)にアクセスでeditアクションだけで完了でしたが、 12章ではメールリンクを踏むとフォーム画面を描画して、フォーム画面の入力を完了するとパスワードの変更完了という流れですので、 パスワード変更フォーム画面の描画をnew、パスワード変更の投稿をeditでしますので、newとeditアクションとURLがそれぞれ必要になるようです。

rails generate controller PasswordResets new edit --no-test-framework

そして新しいリソースとして以下を設定します

resources :password_resets,     only: [:new, :create, :edit, :update]
HTTPリクエス URL Action 名前付きルート
GET /password_resets/new new new_password_reset_path
POST /password_resets create password_resets_path
GET /password_resets//edit edit edit_password_reset_url(token)
PATCH /password_resets/ update password_reset_url(token)

ログイン画面にパスワード再設定画面へのリンクを追加して
reset_digest属性とreset_sent_at属性をUserモデルに追加、
app/views/password_resets/new.html.erbにパスワード再設定フォーム画面を作り、
コントローラ部分とメイラー部分を作っていきます。


12.3.1 editアクションで再設定

今回はeditアクション(メールリンクからアクセスした時のアクション)の他に、updateアクションがあり、両方でメールアドレス情報が必要です。 パスワードの再設定では、editアクションでパスワードの再設定フォーム画面を表示させ、そのフォームのパスワード情報をupdateアクションでデータベースに反映させます。 editアクションはリンクからメールアドレス情報を取得すればいいのですが、こフォームにはパスワード入力しかないのでupdateアクションは別の方法メールアドレス情報を取得しなければなりません。

そこで、editアクションで描画されたフォーム画面edit.html.erbから値を引き継ぐために、隠しフィールドとしてページ内にメールアドレスを保存する手法を取ります。

リスト 12.14: パスワード再設定のフォーム
app/views/password_resets/edit.html.erb
 <% provide(:title, 'Reset password') %>
<h1>Reset password</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= hidden_field_tag :email, @user.email %>                 #ここが隠しフィールド

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Update password", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>
12.3.2 パスワードを更新する

以下のコードの意味を少し忘れてしまっていたので、復習。

    def user_params
      params.require(:user).permit(:password, :password_confirmation)
    end

require メソッドを利用することで、引数に設定した key の 値だけを取得することができ、

permit メソッドは許可したいパラメータだけをフィルタしてくれるようです。

つまり上のコードはパラメーターのキー:user内のpasswordとpassword_confirmationのみを受け取るということになる、という意味かな? paramsから受け取る情報を制限するコードです


今回はだいたい前章と同じような内容だったため、割とすんなり理解できました。 SendGridも自力の試行錯誤の結果使えるようになったのは嬉しかったです。 次回はログイン機構から離れ、いよいよ投稿機能に移っていくようで楽しみです。


12章のまとめ
  • パスワードの再設定は Active Recordオブジェクトではないが、セッションやアカウント有効化の場合と同様に、リソースでモデル化できる

  • パスワードを再設定させるために、生成したトークンを使って一意のURLを作る

  • より安全なパスワード再設定のために、ハッシュ化したトークン (ダイジェスト) を使う

  • メイラーのテストと統合テストは、どちらもUserメイラーの振舞いを確認するのに有用

  • SendGridなどの外部のサービスを使う時は、そのサービスが実際に上手く動くかも考慮に入れる必要がある。