12.15では次のコードを使っています。params[:id])上のコードを下のコードと比べてみましょう。11.28で使われたコードです。11.31で使ったコードです。11.1で示した認証メソッドであり、また、今回追加したコードですべて実装が完了したことになります。12.11のリンクを開いたときに、パスワード再設定のフォームが出力されるようになりました。12.11のようになります。パスワード再設定のフォーム演習12.2.1.1で示した手順に従って、Railsサーバーのログから送信メールを探し出し、そこに記されているリンクを見つけてください。12.11のように表示されるか確かめてみましょう。先ほど表示したページから、実際に新しいパスワードを送信してみましょう。パスワードを更新するAccountActivationsコントローラのeditアクションでは、ユーザーの有効化ステータスをfalseからtrueに変更しましたが、今回の場合はフォームから新しいパスワードを送信するようになっています。したがって、フォームからの送信に対応するupdateアクションが必要になります。このupdateアクションでは、次の4つのケースを考慮する必要があります。どのように対応すれば良いのかあまり明確ではなさそうです。上のケースを1つずつ対応していくことにしましょう。ついては、editとupdateアクションに次のようなメソッドとbeforeフィルターを用意することで対応できそうです。対応案このcheck_expirationメソッドは、有効期限をチェックするPrivateメソッドとして定義します。endend上のcheck_expirationメソッドでは、期限切れかどうかを確認するインスタンスメソッド「password_reset_expired?」を使っています。この新しいメソッドについては後ほど説明することにします。12.16になります)。ケースに対応することができそうです。12.14のパーシャルにエラーメッセージが表示されるようにすれば解決できます。同様の処理を進めていけば問題なさそうです。今回の小難しい問題点は、パスワードが空文字だった場合の処理です。いう実装をしたからです。したがって、このケースについては明示的にキャッチするコードを追加する必要があります3。これを解決する方法として、今回は@userオブジェクトにエラーメッセージを追加する方法をとってみます。具体的には、次のようにerrors.addを使ってエラーメッセージを追加します。:blank)このように書くと、パスワードが空だった時に空の文字列に対するデフォルトのメッセージを表示してくれるようになります。endend(上のコードでは、7.3.2で実装したときと同様に、user_paramsメソッドを使ってpasswordとpassword_confirmation属性を精査している点に注意してください。12.16の実装だけです。今回は先回りして、始めからUserモデルに移譲する前提で次のようにコードを書いていました。@user.password_reset_expired?上のコードを動作させるために、password_reset_expired?メソッドをUserモデルで定義していきましょう。12.2.1を参考に、このメソッドではパスワード再設定の期限を設定して、2時間以上パスワードが再設定されなかった場合は期限切れとする処理を行います。これをRubyで表現すると次のようになります。記号を「〜より少ない」と読んでしまうと、「パスワード再設定メール送信時から経過した時間が、2時間より少ない場合」となってしまい、困惑してしまうので注意してください。ここで行っている処理は、「少ない」ではなく「早い」と捉えると理解しやすいです。記号を「〜より早い時刻」と読んでください。期待どおりの条件となります。(この比較の公式な証明を12.6に付録として追加しました)。12.16のupdateアクションが動作するようになります。(確認のために2時間も待っていられないので、テストにはもう1つ分岐を追加していますが、これは12.3.3.1の演習に回すことにします)。ブラウザで表示し、passwordとconfirmationの文字列をわざと間違えて送信してみましょう。どんなエラーメッセージが表示されるでしょうか?コンソールに移り、パスワード再設定を送信したユーザーオブジェクトを見つけてください。見つかったら、そのオブジェクトのpassword_digestの値を取得してみましょう。パスワードの再設定は成功したら、再度password_digestの値を取得し、先ほど取得した値と異なっていることを確認してみましょう。新しい値はuser.reloadを通して取得する必要があります。(前述のとおり、3番目の分岐については12.3.3.1の演習に回します)。パスワード再設定のテストファイルを生成しましょう。と多くの共通点がありますが、テストの冒頭部分には次のような違いがあります。password」フォームを表示して無効なメールアドレスを送信し、次はそのフォームで有効なメールアドレスを送信します。後者ではパスワード再設定用トークンが作成され、再設定用メールが送信されます。続いて、メールのリンクを開いて無効な情報を送信し、次にそのリンクから有効な情報を送信して、それぞれが期待どおりに動作することを確認します。12.18に示します。このテストはコードリーディングのよい練習台になりますので、みっちりお読みください。12.18で使っているアイデアの大半は、本チュートリアルで既出です。今回の新しい要素はinputタグぐらいでしょう。user.email上のコードは、inputタグに正しい名前、type="hidden"、メールアドレスがあるかどうかを確認します。greenになるはずです。12.6にあるcreate_reset_digestメソッドはupdate_attributeを2回呼び出していますが、これは各行で1回ずつデータベースへ問い合わせしていることになります。(これでデータベースへの問い合わせが1回で済むようになります)。greenになることも確認してください。解答も含まれています。コードにあるresponse.bodyは、そのページのHTML本文をすべて返すメソッドです)。(なお、大文字と小文字は区別されません)。2時間経ったらパスワードを再設定できなくする方針は、セキュリティ的に好ましいやり方でしょう。良くする方法はまだあります。コンピューターでパスワード再設定が行われた場合を考えてみてください。(しかもそのままログイン機構まで突破されてしまいます!)。12.22のコードを追加し、パスワードの再設定に成功したらダイジェストをnilになるように変更してみましょう5。12.18に1行追加し、1つ前の演習課題に対するテストを書いてみましょう。11.33のuser.reloadメソッドを組み合わせて、reset_digest属性を直接テストしてみましょう。(再掲)これでパスワード再設定の実装も終わりました。あとは前章と同様に、development環境だけでなくproduction環境でも動くようにするだけです。セットアップの手順はアカウント有効化と全く同じです。12.24までスキップしてしまっても大丈夫です。(このアドオンを利用するためにはHerokuアカウントにクレジットカードを設定する必要がありますが、アカウント検証では料金は発生しません)。tier」というサービスを使うことにします。1日のメール数が最大400通までという制限がありますが、無料で利用することができます。アドオンをアプリケーションに追加するには、次のコマンドを実行します。herokuコマンドのバージョンが古いとここで失敗するかもしれません。Toolbeltを使って最新版に更新するか、次の古い文法のコマンドを試してみてください。sendgrid:starterアプリケーションでSendGridアドオンを使うには、production環境のSMTPに情報を記入する必要があります。12.23に示したとおり、本番Webサイトのアドレスをhost変数に定義する必要もあります。11.41のメール設定にはSendGridアカウントのuser_nameとpassword設定を記入する行もありますが、そこには記入せず、必ず環境変数「ENV」に設定するよう十分ご注意ください。本番運用するアプリケーションでは、暗号化されていないIDやパスワードのような重要なセキュリティ情報は「絶対に」ソースコードに直接書き込まないでください。そのような情報は環境変数に記述し、そこからアプリケーションに読み込む必要があります。今回の場合、そうした変数はSendGridアドオンが自動的に設定してくれますが、13.4.4では環境変数を自分で設定しなければなりません。password-reset続いてリモートリポジトリにプッシュし、Herokuにデプロイします。12.14のようなメールが送信されてくるはずです。記載されているリンクをクリックし、無効なパスワードと有効なパスワードをそれぞれ試してみましょう。12.13のような結果を得られるはずです。production環境から送信したパスワード再設定メール演習production環境でユーザー登録を試してみましょう。ユーザー登録時に入力したメールアドレスにメールは届きましたか?メールを受信できたら、実際にメールをクリックしてアカウントを有効化してみましょう。Heroku上のログを調べてみて、有効化に関するログがどうなっているのか調べてみてください。logsコマンドを実行してみましょう。アカウントを有効化できたら、今度はパスワードの再設定を試してみましょう。最後にパスワード再設定の実装が終わったことにより、サンプルアプリケーションのユーザー登録・ログイン・ログアウトの仕組みは、本物のアプリケーションと近いレベルに仕上がりました。実装していきましょう。多数紹介する予定です。期限切れの比較12.3では、パスワードの期限が切れたかどうかを調べるために、次の比較を行いました。12.17で説明したように、この式を「少ない」と解釈すると逆の意味になってしまいますので、「早い」と解釈してみてください6。最初に、期間を2つ定義します。パスワードの再設定は、メールが送信された時刻から経過した期間が、有効期間よりも長くなった場合に「期限切れ」となります。これを次のように表します。\)と表すと、次の2つの関係式を得ることができます。(12.1)に代入すると、次の結果が得られます。\)をかけると、次の式が得られます。12.17のpassword_reset_expired?メソッドと同じコードになります。2.hours.agoend12.3でも説明したとおり、<記号を「〜より少ない」ではなく「〜より早い時刻」と解釈すれば、「パスワードの再設定は、現在より2時間以上前の時刻に行われた」という言明と一致します。本章は他の章からほぼ独立しています。11.6によるメイラーの生成部分です。いえ、本章の内容は第11章と似通っている部分も多いので、そちらの章を進めてから本章に取り掛かった方が理解が容易になるでしょう。あるセキュリティに対する懸念の1つに「そのメールアドレスが登録されているかどうかを表示してしまってよいのか?」というものがありますが、この懸念は見当はずれです。ユーザー登録のフォームで「そのメールアドレスが既に使われているかどうか」をチェックしていて、その結果を表示しているからです。このため、メールアドレスが使われているかどうかの情報を今回表示したとしても、クラッカーに対して何ら新しい情報を与えていないことになります。この場合、パスワードフィールドが空である場合だけを扱います。パスワードの確認フィールドが空の場合は、確認フィールドのバリデーションで検出され、エラーメッセージが表示されるので不要です。パスワードフィールドとパスワード確認フィールドが両方空だとバリデーションがスキップされてしまいます。:blank)を使った方が便利だと指摘してもらいました。元々は英語でエラーメッセージを書いていましたが、blankオプションに切り替わりました)。このような機能の提案と実装だけでなく、説明文まで提供していただきました。この証明は物理学で博士号を取得した人間が書いているので、きっと読む価値があると思います。いった式を単純明快に説明するのは至難のワザでした...。株式会社によって運営されています。基づく表記プライバシーポリシーお問い合わせTIPS原著者からのメッセージ目次コードサンプルみんなのつぶやきRailsガイド。