11.1.1
演習
現時点でテストスイートを実行すると greenになることを確認してみましょう。
表 11.2の名前付きルートでは、_pathではなく_urlを使うように記してあります。なぜでしょうか? 考えてみましょう。ヒント: 私達はこれからメールで名前付きルートを使います。
1確認
2メールからリンクを開いてアクセスするため
11.1.2
演習
本項での変更を加えた後、テストスイートが green のままになっていることを確認してみましょう。
コンソールからUserクラスのインスタンスを生成し、そのオブジェクトからcreate_activation_digestメソッドを呼び出そうとすると (Privateメソッドなので) NoMethodErrorが発生することを確認してみましょう。また、そのUserオブジェクトからダイジェストの値も確認してみましょう。
リスト 6.34で、メールアドレスの小文字化にはemail.downcase!という (代入せずに済む) メソッドがあることを知りました。このメソッドを使って、リスト 11.3のdowncase_emailメソッドを改良してみてください。また、うまく変更できれば、テストスイートは成功したままになっていることも確認してみてください。
1確認
2
>> user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: false, activation_digest: nil, activated: false, activated_at: nil>
>> user.create_activation_digest
Traceback (most recent call last):
1: from (irb):2
NoMethodError (private method `create_activation_digest' called for #<User:0x00000000032badb0>)
Did you mean? restore_activation_digest!
3
def downcase_email
self.email.downcase!
end
selfをつけなくてもテストでエラーは出ないが
modelクラスの中でのselfの使い方
によると
ちなみに使い分けですが、インスタンスメソッドはそれぞれのインスタンスに対して参照・更新するようなメソッドとして使います。一方クラスメソッドは、modelクラスのレコードを検索するとか、作成されたインスタンスの数をカウントするとか、クラスの新しいインスタンスを作る等、個々のインスタンスには紐づけずクラスに対して働きかけるメソッドになります。
とあるのでクラスメソッドにした方がいいのではないかなと思う
create_activation_digestもself.ついてるので
しかしインスタントメソッド内でself.をつかうとインスタすメソッドになるのでこれはクラスメソッドにするためのselfではない??
class<<self
endで囲われてなかったり
def User.~となっていなかったりdef self.~やメソッド内でself.class.hoge~となっていないのでクラスメソッドではないと判断したが会っているのかな?
11.2.1
演習
コンソールを開き、CGIモジュールのescapeメソッド (リスト 11.15) でメールアドレスの文字列をエスケープできることを確認してみましょう。このメソッドで"Don’t panic!"をエスケープすると、どんな結果になりますか?
>> CGI.escape('Don’t panic!')
=> "Don%E2%80%99t+panic%21"
11.2.2
演習
Railsのプレビュー機能を使って、ブラウザから先ほどのメールを表示してみてください。「Date」の欄にはどんな内容が表示されているでしょうか?
Mon, 22 Apr 2019 01:44:05 +0000
GMT時間でアクセスした日時表示
11.2.3
演習
この時点で、テストスイートが greenになっていることを確認してみましょう。
リスト 11.20で使ったCGI.escapeの部分を削除すると、テストが redに変わることを確認してみましょう。
1
確認
2
n----==_mimepart_5cbd2c00cb0fa_140cbc99a4665c3\r\nContent-Type: text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nHi Michael Example,\r\n\r\nWelcome to the Sample App! Click on the link below to activate your account:\r\n\r\nhttp://dfa974f98d004f37899984bee93a2473.vfs.cloud9.us-east-2.amazonaws.com/account_activations/cmK5mEK4rCiqcyWEM67KyA/edit?email=michael%40example.com\r\n\r\n----==_mimepart_5cbd2c00cb0fa_140cbc99a4665c3\r\nContent-Type: text/html;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\n<!DOCTYPE html>\r\n<html>\r\n <head>\r\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n <style>\r\n /* Email styles need to be inline */\r\n </style>\r\n </head>\r\n\r\n <body>\r\n <h1>Sample App</h1>\r\n\r\n<p>Hi Michael Example,</p>\r\n\r\n<p>\r\nWelcome to the Sample App! Click on the link below to activate your account:\r\n</p>\r\n\r\n<a href=\"http://dfa974f98d004f37899984bee93a2473.vfs.cloud9.us-east-2.amazonaws.com/account_activations/cmK5mEK4rCiqcyWEM67KyA/edit?email=michael%40example.com\">Activate</a>\r\n </body>\r\n</html>\r\n\r\n----==_mimepart_5cbd2c00cb0fa_140cbc99a4665c3--\r\n".
test/mailers/user_mailer_test.rb:14:in `block in <class:UserMailerTest>'
41/41: [=========] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.55150s
41 tests, 171 assertions, 1 failures, 0 errors, 0 skips
11.2.4
演習
新しいユーザーを登録したとき、リダイレクト先が適切なURLに変わったことを確認してみましょう。その後、Railsサーバーのログから送信メールの内容を確認してみてください。有効化トークンの値はどうなっていますか?
コンソールを開き、データベース上にユーザーが作成されたことを確認してみましょう。また、このユーザーはデータベース上にはいますが、有効化のステータスがfalseのままになっていることを確認してください。
1
Redirected to https://dfa974f98d004f37899984bee93a2473.vfs.cloud9.us-east-2.amazonaws.com/
ルートディレクトリになっている
2
>> user = User.find(101)
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 101], ["LIMIT", 1]]
=> #<User id: 101, name: "test01", email: "test01@example.org", created_at: "2019-04-22 05:18:28", updated_at: "2019-04-22 05:18:28", password_digest: "$2a$10$rPJDdcoRU/M9dkyv/X5hKehWF24P25FKLFq4mIPWA4T...", remember_digest: nil, admin: false, activation_digest: "$2a$10$IyKVaC6xJh2zfGTywkFUhuaY8JnePJer1j4jKPFYsJw...", activated: false, activated_at: nil>
>> user.activated?
=> false
11.3.1
演習
コンソール内で新しいユーザーを作成してみてください。新しいユーザーの記憶トークンと有効化トークンはどのような値になっているでしょうか? また、各トークンに対応するダイジェストの値はどうなっているでしょうか?
リスト 11.26で抽象化したauthenticated?メソッドを使って、先ほどの各トークン/ダイジェストの組み合わせで認証が成功することを確認してみましょう。
>> user = User.create(name: "test1131",email: "test@mail.org", password: "123456")
(0.1ms) begin transaction
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ? [["email", "test@mail.org"], ["LIMIT", 1]]
SQL (2.8ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest", "activation_digest") VALUES (?, ?, ?, ?, ?, ?) [["name", "test1131"], ["email", "test@mail.org"], ["created_at", "2019-04-22 09:15:50.439813"], ["updated_at", "2019-04-22 09:15:50.439813"], ["password_digest", "$2a$10$Vz24S0K53ErWqPOMThXBbOLJ5c.IqzV4LhT2Am07tNANWysk9vrUq"], ["activation_digest", "$2a$10$glOElS8hLRrrL7S6oU7HbeGa2YNAK8SY6eNmz4Y3ebu6LI3bw5ky2"]]
(7.2ms) commit transaction
=> #<User id: 102, name: "test1131", email: "test@mail.org", created_at: "2019-04-22 09:15:50", updated_at: "2019-04-22 09:15:50", password_digest: "$2a$10$Vz24S0K53ErWqPOMThXBbOLJ5c.IqzV4LhT2Am07tNA...", remember_digest: nil, admin: false, activation_digest: "$2a$10$glOElS8hLRrrL7S6oU7HbeGa2YNAK8SY6eNmz4Y3ebu...", activated: false, activated_at: nil>
>> user.remember_token
=> nil
>> user.activation_token
=> "cCxeiFM8zoy1ziofmOnrcA"
>> user.remember_digest
=> nil
>> user.activation_digest
=> "$2a$10$glOElS8hLRrrL7S6oU7HbeGa2YNAK8SY6eNmz4Y3ebu6LI3bw5ky2"
>>
2
>> user.remember_token = User.new_token
=> "ixM6QvBSTvD-UIFn16IpvA"
>> user.update_attribute(:remember_digest, User.digest(user.remember_token))
(0.1ms) begin transaction
SQL (2.6ms) UPDATE "users" SET "updated_at" = ?, "remember_digest" = ? WHERE "users"."id" = ? [["updated_at", "2019-04-23 11:33:13.345380"], ["remember_digest", "$2a$10$Blp7ueOFh/3xEb9iErYT1uwR9I6T4qo0SrFuqBH0i9Y1ddAApScyC"], ["id", 102]]
(5.7ms) commit transaction
=> true
11.3.3
演習
リスト 11.35にあるactivateメソッドはupdate_attributeを2回呼び出していますが、これは各行で1回ずつデータベースへ問い合わせしていることになります。リスト 11.39に記したテンプレートを使って、update_attributeの呼び出しを1回のupdate_columns呼び出しにまとめてみましょう (これでデータベースへの問い合わせが1回で済むようになります)。また、変更後にテストを実行し、 greenになることも確認してください。
現在は、/usersのユーザーindexページを開くとすべてのユーザーが表示され、/users/:idのようにIDを指定すると個別のユーザーを表示できます。しかし考えてみれば、有効でないユーザーは表示する意味がありません。そこで、リスト 11.40のテンプレートを使って、この動作を変更してみましょう9。なお、ここで使っているActive Recordのwhereメソッドについては、13.3.3でもう少し詳しく説明します。
ここまでの演習課題で変更したコードをテストするために、/users と /users/:id の両方に対する統合テストを作成してみましょう。
1
update_columns(activated: true, activated_at: Time.zone.now)
2
def index
@users = User.where(activated: ture).paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
redirect_to root_url and return unless @user.activated?
end
3