演習1
現時点でテストスイートを実行すると green になることを確認してみましょう。
何も問題がなければGREENになるはずです
表 11.2の名前付きルーティングに_pathではなく_urlを使っている理由を考えてみましょう。(ヒント: 私たちはこれから名前付きルーティングをメールで使います。)
_path は例えば
user_path
→'/user'
のようにrails 内で使用されているルートであれば_pathを使用できるという事です
_urlは
'http://www.example.com/user'
のように完全なURLを返してあげる必要があります。
それは_pathと違い外部からのアクセスとなるためです
まあ_pathは家では"花子ちゃん"でも良いけど
_urlは、外に出たら"山田花子さん"と呼びなさいって感じですかね(意味不明)
演習2
本節の変更を加えた後も、テストスイートが引き続き green になることを確認してみましょう。
rails testを行い、GREENになっていたらOKです
コンソールからUserクラスのインスタンスを生成し、そのオブジェクトからcreate_activation_digestメソッドを呼び出そうとすると、PrivateメソッドなのでNoMethodErrorが発生することを確認してみましょう。また、そのUserオブジェクト内のダイジェストの値も確認してみましょう。
user = User.first
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=>
#<User:0x00007ff385e78c88
...
user.create_activation_digest
/usr/local/rvm/gems/default/gems/activemodel-7.0.4.3/lib/active_model/attribute_methods.rb:455:in `method_missing': private method `create_activation_digest' called for #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2023-10-01 08:28:59.861078000 +0000", updated_at: "2023-10-01 08:28:59.861078000 +0000", password_digest: [FILTERED], remember_digest: nil, admin: true, activation_digest: "$2a$12$pkJnv9FWgk753jd0oPM4TeV7y4P2q7fZNgfTXZH.D.A...", activated: true, activated_at: "2023-10-01 08:28:59.606888000 +0000"> (NoMethodError)
Did you mean? restore_activation_digest!
この中の
activation_digest: "$2a$12$pkJnv9FWgk7・・・
がダイジェスト。
トークンが有効化されていますね。
リスト 6.35で、メールアドレスの小文字化にはemail.downcase!という代入不要なメソッドもあることを学びました。このメソッドを使って、リスト 11.3のdowncase_emailメソッドを改良してみてください。また、うまく変更できれば、テストスイートは成功したままになっていることも確認してみてください。
app/models/user.rb
private
# メールアドレスをすべて小文字にする
def downcase_email
self.email = email.downcase
end
# 有効化トークンとダイジェストを作成および代入する
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end
のdowncase_emailメソッド内を以下に変更しましょう
# メールアドレスをすべて小文字にする
def downcase_email
email.downcase!
end
これでrails testを実行してみてGREENであることを確認してみましょう
演習3
Railsコンソールを開き、CGIモジュールのescapeメソッド(リスト 11.15)でメールアドレスの文字列をエスケープできることを確認してみましょう。このメソッドで"Don't panic!"をエスケープすると、どんな結果になりますか?
CGI.escape("Don't panic!")
=> "Don%27t+panic%21"
演習4
Railsのプレビュー機能を使って、ブラウザから先ほどのメールを表示してみてください。「Date」の欄にはどんな内容が表示されているでしょうか?
その名の通り、現在の日付が入っています
演習5
この時点で、テストスイートが green になっていることを確認してみましょう。
GREENになればOKです
リスト 11.20で使ったCGI.escapeの部分を削除すると、テストが red に変わることを確認してみましょう。
演習6
新しいユーザーを登録したとき、リダイレクト先が適切なURLに変わったことを確認してみましょう。その後、Railsサーバーのログから送信メールの内容を確認してみてください。有効化トークンの値はどうなっていますか?
下記のようにauthenticity_tokenがハッシュ化されています
Processing by UsersController#create as TURBO_STREAM
Parameters: {"authenticity_token"=>"h1SQidx5juySt_ZX_7u9XT_bYE3BSFoJrLbeqfWY8nb0ufphkv0WVZPFUUY-w712CLnoDLxDptVaksFQM3ggQA", "user"=>{"name"=>"ryoryo", "email"=>"ryoryoryo@gmail.com", "password"=>"password", "password_confirmation"=>"password"}, "commit"=>"Create my account"}
補足
もしauthenticity_token"=>[FILTERD]となっている場合は
config/initializers/filter_parameter_logging.rb |
---|
の中にある
# Be sure to restart your server when you modify this file.
# Configure parameters to be filtered from the log file. Use this to limit dissemination of
# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
# notations and behaviors.
#Rails.application.config.filter_parameters += [
#:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
#]
コメントアウトしてみてください。ハッシュ化されたauthenticity_tokenが表示されるはずです。
この中にある要素をフィルタリングしてくれます。今回はtokenという名前が付いているのでフィルタリングしてしまっているので、一時的にコメントアウトすれば表示されます。
コンソールを開き、データベース上にユーザーが作成されたことを確認してみましょう。また、このユーザーはデータベース上にはいますが、有効化のステータスがfalseのままになっていることを確認してください。
最後に作成したユーザーを表示してみます。
activateがfalseであることを確認しましょう
User.last
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ? [["LIMIT", 1]]
=>
#<User:0x00007f71081be240
id: 109,
name: "ryoryo",
email: "ryoryoryo@gmail.com",
created_at: Mon, 02 Oct 2023 06:23:40.926093000 UTC +00:00,
updated_at: Mon, 02 Oct 2023 06:23:40.926093000 UTC +00:00,
password_digest: "[FILTERED]",
remember_digest: nil,
admin: false,
activation_digest: "$2a$12$qOwZtLpGmyt4bQtr6cKShOuV7gUW4lNUp/xfPi21gKAnnzx01MAwK",
activated: false,
activated_at: nil>
演習7
コンソール内で新しいユーザーを作成してみてください。新しいユーザーの記憶トークンと有効化トークンはどのような値になっているでしょうか? また、各トークンに対応するダイジェストの値はどうなっているでしょうか?
User.create(name: "ryouko", email: "ryouko@example.com", password: "password", password_confirmation: "password")
(出力、略)
user = User.last
user.remember_token
=> nil
user.remember_digest
=> nil
user.activation_token
=> "zg-CQQ4nTz60g0auoBff2Q"
user.activation_digest
=> "$2a$12$bzGtLdXEGenz8Umqzpt3huYm8RstXrztmDv3AwZJzf29Nh98Hr932"
リスト 11.26で抽象化したauthenticated?メソッドを使って、先ほどの各トークン/ダイジェストの組み合わせで認証が成功することを確認してみましょう。
user.authenticated?(:activation, user.activation_token)
=> true
演習8
11.2.4で生成したメールに含まれているURLをRailsコンソールで調べてみてください。URLのどの部分に有効化トークンが含まれているでしょうか?
新規ユーザーを登録した際に、ログでメールが確認できるはずです。それを調べてみましょう
<p>
Welcome to the Sample App! Click on the link below to activate your account:
</p>
<a href="https://<hex string>.app.github.dev/account_activations/7KnO69jec0OEOMCVrzO9aA/edit?email=hahaha%40gmail.com">Activate</a>
</body>
</html>
ここの
account_activations/7KnO69jec0OEOMCVrzO9aA |
---|
の部分が有効化トークンとなっています
先ほど見つけたURLをブラウザに貼り付けて、そのユーザーの認証に成功し、有効化できることを確認してみましょう。また、有効化ステータスがtrueになっていることをコンソールから確認してみてください。
演習でやったURLを貼り付けてみましょう
私のURLは紛らわしいのですが、この部分です
/account_activations/7KnO69jec0OEOMCVrzO9aA/edit?email=hahaha%40gmail.com
ここをrailsのURLの後ろに貼り付けることでactivationに成功しました
続いて有効かステータスを調べてみましょう
user = User.last
user.activated
=> true
演習9
リスト 11.36にあるactivateメソッドはupdate_attributeを2回呼び出していますが、これは各行で1回ずつデータベースへ問い合わせしていることになります。リスト 11.40に記したテンプレートを使って、update_attributeの呼び出しを1回のupdate_columns呼び出しにまとめてみましょう。これでデータベースへの問い合わせが1回で済むようになります。変更後にテストを実行し、 green になることも確認してください。(注: update_columnsはバリデーションが実行されない上、update_attributeと異なりモデルのコールバックも行われないため、本チュートリアル以外で使用する際は注意が必要です。)
単純にこのようにまとめてしまえばOKです
def activate
update_columns(activated: true, activated_at: Time.zone.now)
end
現在は、/usersのユーザーindexページを開くとすべてのユーザーが表示され、/users/:idのようにIDを指定すると個別のユーザーを表示できます。しかし考えてみれば、有効でないユーザーは表示する意味がありません。そこで、リスト 11.41のテンプレートを使って、この動作を変更してみましょう10 。なお、このテンプレートで使っているActive Recordのwhereメソッドについては、13.3.3でもう少し詳しく説明します。
def index
@users = User.where(activated: true).paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
redirect_to root_url and return unless @user.activated?
end
ここまでの演習課題で変更したコードをテストするために、/usersと/users/:idの両方に対する統合テストを作成してみましょう。/usersテストのテンプレートはリスト 11.42に示されています(本節の手法をリスト 10.63に適用した結果も示されています)。users/:idについては、rails generate integration_test user_showを実行してから、リスト 11.43に示すように無効なfixtureユーザを追加してください。対応するテストのテンプレートはリスト 11.44に示されています。
いろいろ検証してみましたが、ここはいったんパスします。また解答が分かり次第更新します。
演習10
実際に本番環境でユーザー登録をしてみましょう。ユーザー登録時に入力したメールアドレスにメールは届きましたか?
チュートリアルに従ってmailgunやrenderで設定をして、実際にユーザー登録してみましょう。
登録後入力したメールアドレスにactivationのメールが来るのでactiveすればログインできるはずです
メールを受信できたら、実際にメールをクリックしてアカウントを有効化してみましょう。また、Render上のログを調べてみて、有効化に関するログがどうなっているのか調べてみてください。
render上のログは下記の場所から見れるはずです。有効化されたログは恐らくここだと思われます