yutokyokutyo / rebuild_sample_app

https://railstutorial.jp/chapters/static_pages?version=5.0#cha-static_pages
https://rebuildsampleapp.herokuapp.com/
5 stars 0 forks source link

14章 #26

Closed yutokyokutyo closed 7 years ago

yutokyokutyo commented 7 years ago

オーバービュー

img_1983 img_0106

yutokyokutyo commented 7 years ago

14.1.1

  1. 図 14.7のid=1のユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。ヒント: 4.3.2で紹介したmap(&:method_name)のパターンを思い出してください。例えばuser.following.map(&:id)の場合、idの配列を返します。

ref: http://ref.xaio.jp/ruby/classes/symbol/to_proc

>> user.following.map { |char| char.downcase }
>> user.following.map(&:downcase)
  1. 図 14.7を参考にして、id=2のユーザーに対してuser.followingを実行すると、結果はどのようになるでしょうか? また、同じユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。
[4] pry(main)> user.following.map(&:id)
NoMethodError: undefined method `following' for #<User:0x007fcbb75a0890>
from /usr/local/lib/ruby/gems/2.3.0/gems/activemodel-5.0.2/lib/active_model/attribute_methods.rb:433:in `method_missing'

model/user.rb にfollowingメソッドを書いてないから結果が出ない。この先実装することになりそう。 本来だったらuserがフォローした人たちのidが全て表示されるはず。

想像させるだけで結果がでないいじわる問題だった 👹

yutokyokutyo commented 7 years ago
  1. コンソールを開き、表 14.1のcreateメソッドを使ってActiveRelationshipを作ってみましょう。データベース上に2人以上のユーザーを用意し、最初のユーザーが2人目のユーザーをフォローしている状態を作ってみてください。
[3] pry(main)> user
=> #<User:0x007fcbbd5f3e18
 id: 1,
 name: "Example User",
 email: "example@railstutorial.org",
 created_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 updated_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 password_digest: "$2a$10$JnryGamXGsUE7zUtRtYfw./7rrUoRjAjcwrBxG/rrWB2OnoQCwBQm",
 remember_digest: nil,
 admin: true,
 activation_digest: "$2a$10$Mra/ZztIYV8g.Gw70gJ0j.uFkr8lXj8pEmWwYoOmpS.0hRURblun2",
 activated: true,
 activated_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 reset_digest: nil,
 reset_sent_at: nil>
[4] pry(main)>
[4] pry(main)> user.active_relationships.create(followed_id: User.second.id)
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
   (0.1ms)  begin transaction
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (1.4ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", 2017-05-13 08:42:20 UTC], ["updated_at", 2017-05-13 08:42:20 UTC]]
   (0.8ms)  commit transaction
=> #<Relationship:0x007fcbb85a1780
 id: 1,
 follower_id: 1,
 followed_id: 2,
 created_at: Sat, 13 May 2017 08:42:20 UTC +00:00,
 updated_at: Sat, 13 May 2017 08:42:20 UTC +00:00>
[6] pry(main)> user.active_relationships
  Relationship Load (0.2ms)  SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ?  [["follower_id", 1]]
=> [#<Relationship:0x007fcbb85a1780
  id: 1,
  follower_id: 1,
  followed_id: 2,
  created_at: Sat, 13 May 2017 08:42:20 UTC +00:00,
  updated_at: Sat, 13 May 2017 08:42:20 UTC +00:00>]
  1. 先ほどの演習を終えたら、active_relationship.followedの値とactive_relationship.followerの値を確認し、それぞれの値が正しいことを確認してみましょう。
[68] pry(main)> active_relationship = Relationship.first
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" ORDER BY "relationships"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Relationship:0x007fcbb779ba78
 id: 1,
 follower_id: 1,
 followed_id: 2,
 created_at: Sat, 13 May 2017 08:42:20 UTC +00:00,
 updated_at: Sat, 13 May 2017 08:42:20 UTC +00:00>
[74] pry(main)> active_relationship.followed.id
=> 2
[75] pry(main)> active_relationship.follower.id
=> 1
yutokyokutyo commented 7 years ago

コンソールを開き、リスト 14.9のコードを順々に実行してみましょう。

[4] pry(main)> michael = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User:0x007fcbb7a7fe60
 id: 1,
 name: "Example User",
 email: "example@railstutorial.org",
 created_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 updated_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 password_digest: "$2a$10$JnryGamXGsUE7zUtRtYfw./7rrUoRjAjcwrBxG/rrWB2OnoQCwBQm",
 remember_digest: nil,
 admin: true,
 activation_digest: "$2a$10$Mra/ZztIYV8g.Gw70gJ0j.uFkr8lXj8pEmWwYoOmpS.0hRURblun2",
 activated: true,
 activated_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 reset_digest: nil,
 reset_sent_at: nil>
[5] pry(main)> archer  = User.second
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User:0x007fcbb7bb8a20
 id: 2,
 name: "Nona Keebler",
 email: "example-1@railstutorial.org",
 created_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 updated_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 password_digest: "$2a$10$RlxVmNFEa99VmYbS6NgWDe3wqCgQf.VbKbSHZgh2lLmvZifrPuRlG",
 remember_digest: nil,
 admin: false,
 activation_digest: "$2a$10$R7.tQmxIag.VmdzFpAq4Yu5ZL1Gw4o73bE4vGxeuzAz1xgX17JIxq",
 activated: true,
 activated_at: Sat, 13 May 2017 04:37:48 UTC +00:00,
 reset_digest: nil,
 reset_sent_at: nil>
[6] pry(main)> assert_not michael.following?(archer)
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
NoMethodError: undefined method `assert_not' for main:Object
from (pry):6:in `<main>'
[7] pry(main)> michael.following?(archer)
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> true
[8] pry(main)> michael.unfollow(archer)
  Relationship Load (0.2ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 1], ["followed_id", 2], ["LIMIT", 1]]
   (0.1ms)  begin transaction
  SQL (0.4ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 1]]
   (1.7ms)  commit transaction
=> #<Relationship:0x007fcbbc39f7a8
 id: 1,
 follower_id: 1,
 followed_id: 2,
 created_at: Sat, 13 May 2017 08:42:20 UTC +00:00,
 updated_at: Sat, 13 May 2017 08:42:20 UTC +00:00>
[9] pry(main)> michael.following?(archer)
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> false
[10] pry(main)> michael.follow(archer)
   (0.1ms)  begin transaction
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (0.4ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", 2017-05-13 09:40:06 UTC], ["updated_at", 2017-05-13 09:40:06 UTC]]
   (0.7ms)  commit transaction
=> #<Relationship:0x007fcbbc412618
 id: 2,
 follower_id: 1,
 followed_id: 2,
 created_at: Sat, 13 May 2017 09:40:06 UTC +00:00,
 updated_at: Sat, 13 May 2017 09:40:06 UTC +00:00>
[11] pry(main)> michael.following?(archer)
  User Exists (0.2ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 1], ["id", 2], ["LIMIT", 1]]
=> true

先ほどの演習の各コマンド実行時の結果を見返してみて、実際にはどんなSQLが出力されたのか確認してみましょう。

sqlite> .tables
ar_internal_metadata  relationships         users
microposts            schema_migrations
sqlite> .mode line
sqlite> select * from users inner join relationships on users.id = relationships.followed_id where relationships.follower_id = 1 and users.id = 2 limit 1;
               id = 2
             name = Nona Keebler
            email = example-1@railstutorial.org
       created_at = 2017-05-13 04:37:48.776894
       updated_at = 2017-05-13 04:37:48.776894
  password_digest = $2a$10$RlxVmNFEa99VmYbS6NgWDe3wqCgQf.VbKbSHZgh2lLmvZifrPuRlG
  remember_digest =
            admin = f
activation_digest = $2a$10$R7.tQmxIag.VmdzFpAq4Yu5ZL1Gw4o73bE4vGxeuzAz1xgX17JIxq
        activated = t
     activated_at = 2017-05-13 04:37:48.713530
     reset_digest =
    reset_sent_at =
               id = 2
      follower_id = 1
      followed_id = 2
       created_at = 2017-05-13 09:40:06.977008
       updated_at = 2017-05-13 09:40:06.977008

rails db == sqlite3 db/development.sqlite3 (開発環境)

yutokyokutyo commented 7 years ago
  1. コンソールを開き、何人かのユーザーが最初のユーザーをフォローしている状況を作ってみてください。最初のユーザーをuserとすると、user.followers.map(&:id)の値はどのようになっているでしょうか? 上の演習が終わったら、user.followers.countの実行結果が、先ほどフォローさせたユーザー数と一致していることを確認してみましょう。
[31] pry(main)> user1.followers.map(&:id)
=> [2, 3, 4]
  1. user.followers.countを実行した結果、出力されるSQL文はどのような内容になっているでしょうか?
[33] pry(main)> user1.followers.count
   (0.2ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> 3
  1. また、user.followers.to_a.countの実行結果と違っている箇所はありますか? ヒント: もしuserに100万人のフォロワーがいた場合、どのような違いがあるでしょうか? 考えてみてください。
[34] pry(main)> user1.followers.to_a.count
=> 3

count実行時にSQLが発行されていない!rubyのcountが実行されている。 もしuserに100万人のフォロワーがいた場合、前者はDB上で条件を絞って最低限の処理でcountしているが、後者は100万ものデータをすべて取得してarrayに挿入しcountすることになる。 したがって、前者の書き方が望ましい。

yutokyokutyo commented 7 years ago

14.2.2

  1. コンソールを開き、User.first.followers.countの結果がリスト 14.14で期待している結果と合致していることを確認してみましょう。
  2. 先ほどの演習と同様に、User.first.following.countの結果も合致していることを確認してみましょう。
1] pry(main)> User.first.followers.count
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
   (0.3ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> 38
[2] pry(main)> User.first.following.count
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
   (0.2ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ?  [["follower_id", 1]]
=> 49
yutokyokutyo commented 7 years ago
  1. ブラウザから /users/2 にアクセスし、フォローボタンが表示されていることを確認してみましょう。

image

  1. 同様に、/users/5 では [Unfollow] ボタンが表示されているはずです。

image

  1. さて、/users/1 にアクセスすると、どのような結果が表示されるでしょうか?

image

  1. ブラウザからHomeページとプロフィールページを表示してみて、統計情報が正しく表示されているか確認してみましょう。

image

image

yutokyokutyo commented 7 years ago

14.2.3

  1. ブラウザから /users/1/followers と /users/1/following を開き、それぞれが適切に表示されていることを確認してみましょう。サイドバーにある画像は、リンクとしてうまく機能しているでしょうか?

OK!

  1. リスト 14.29のassert_selectに関連するコードをコメントアウトしてみて、テストが正しく red に変わることを確認してみましょう。
% rails t                                                                                                                     (git)-[following-users]
Running via Spring preloader in process 17557
Started with run options --seed 47713

 FAIL["test_following_page", FollowingTest, 5.769039486000111]
 test_following_page#FollowingTest (5.77s)
        Expected at least 1 element matching "a[href="/users/409608538"]", found 0..
        Expected 0 to be >= 1.
        test/integration/following_test.rb:15:in `block (2 levels) in <class:FollowingTest>'
        test/integration/following_test.rb:14:in `block in <class:FollowingTest>'

 FAIL["test_followers_page", FollowingTest, 5.859068554999794]
 test_followers_page#FollowingTest (5.86s)
        Expected at least 1 element matching "a[href="/users/409608538"]", found 0..
        Expected 0 to be >= 1.
        test/integration/following_test.rb:24:in `block (2 levels) in <class:FollowingTest>'
        test/integration/following_test.rb:23:in `block in <class:FollowingTest>'

  66/66: [=======================================================================================================] 100% Time: 00:00:05, Time: 00:00:05

Finished in 5.88093s
66 tests, 332 assertions, 2 failures, 0 errors, 0 skips
yutokyokutyo commented 7 years ago
  1. ブラウザ上から /users/2 を開き、[Follow] と [Unfollow] を実行してみましょう。うまく機能しているでしょうか? image image image

  2. 先ほどの演習を終えたら、Railsサーバーのログを見てみましょう。フォロー/フォロー解除が実行されると、それぞれどのテンプレートが描画されているでしょうか?

フォロー

Started POST "/relationships" for 127.0.0.1 at 2017-05-15 12:12:35 +0900
Processing by RelationshipsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"U/BGW7cNOMByPTw+MsOfNk5bVWGTvpamzJ6Pu4k8MUHdjCF96HhEXERBIIHQ0YVDpDE5pTBQNimeXuweCWyzYQ==", "followed_id"=>"2", "commit"=>"Follow"}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   (0.0ms)  begin transaction
  CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (0.3ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 101], ["followed_id", 2], ["created_at", 2017-05-15 03:12:35 UTC], ["updated_at", 2017-05-15 03:12:35 UTC]]
   (1.6ms)  commit transaction
Redirected to http://localhost:3000/users/2
Completed 302 Found in 12ms (ActiveRecord: 2.4ms)

Started GET "/users/2" for 127.0.0.1 at 2017-05-15 12:12:35 +0900
Processing by UsersController#show as HTML
  Parameters: {"id"=>"2"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  Rendering users/show.html.erb within layouts/application
   (0.2ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ?  [["follower_id", 2]]
   (0.1ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 2]]
  Rendered shared/_stats.html.erb (6.4ms)
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  User Exists (0.1ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 101], ["id", 2], ["LIMIT", 1]]
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 101], ["followed_id", 2], ["LIMIT", 1]]
  Rendered users/_unfollow.html.erb (2.4ms)
  Rendered users/_follow_form.html.erb (5.9ms)
  Micropost Exists (0.1ms)  SELECT  1 AS one FROM "microposts" WHERE "microposts"."user_id" = ? LIMIT ?  [["user_id", 2], ["LIMIT", 1]]
   (0.1ms)  SELECT COUNT(*) FROM "microposts" WHERE "microposts"."user_id" = ?  [["user_id", 2]]
  Micropost Load (0.2ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? OFFSET ?  [["user_id", 2], ["LIMIT", 30], ["OFFSET", 0]]
  Rendered collection of microposts/_micropost.html.erb [30 times] (95.0ms)
  CACHE (0.0ms)  SELECT COUNT(*) FROM "microposts" WHERE "microposts"."user_id" = ?  [["user_id", 2]]
  Rendered users/show.html.erb within layouts/application (118.2ms)
  Rendered layouts/_rails_default.html.erb (62.8ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  Rendered layouts/_header.html.erb (1.7ms)
  Rendered layouts/_footer.html.erb (0.8ms)
Completed 200 OK in 201ms (Views: 195.3ms | ActiveRecord: 1.2ms)

フォロー解除

Started DELETE "/relationships/90" for 127.0.0.1 at 2017-05-15 12:13:25 +0900
Processing by RelationshipsController#destroy as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"XpatVBG8A7/R8mvOtzaD1IGf23lCyR/0nYzZVAXPkRjQ6spyTsl/I+eOd3FVJJmha/W3veEnv3vPTLrxhZ8TOA==", "commit"=>"Unfollow", "id"=>"90"}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."id" = ? LIMIT ?  [["id", 90], ["LIMIT", 1]]
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 101], ["followed_id", 2], ["LIMIT", 1]]
   (0.0ms)  begin transaction
  SQL (0.2ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 90]]
   (1.8ms)  commit transaction
Redirected to http://localhost:3000/users/2
Completed 302 Found in 9ms (ActiveRecord: 2.9ms)

Started GET "/users/2" for 127.0.0.1 at 2017-05-15 12:13:25 +0900
Processing by UsersController#show as HTML
  Parameters: {"id"=>"2"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  Rendering users/show.html.erb within layouts/application
   (0.1ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ?  [["follower_id", 2]]
   (0.1ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 2]]
  Rendered shared/_stats.html.erb (3.3ms)
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  User Exists (0.3ms)  SELECT  1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ?  [["follower_id", 101], ["id", 2], ["LIMIT", 1]]
  Rendered users/_follow.html.erb (1.8ms)
  Rendered users/_follow_form.html.erb (5.4ms)
  Micropost Exists (0.1ms)  SELECT  1 AS one FROM "microposts" WHERE "microposts"."user_id" = ? LIMIT ?  [["user_id", 2], ["LIMIT", 1]]
   (0.1ms)  SELECT COUNT(*) FROM "microposts" WHERE "microposts"."user_id" = ?  [["user_id", 2]]
  Micropost Load (0.3ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? ORDER BY "microposts"."created_at" DESC LIMIT ? OFFSET ?  [["user_id", 2], ["LIMIT", 30], ["OFFSET", 0]]
  Rendered collection of microposts/_micropost.html.erb [30 times] (110.0ms)
  CACHE (0.0ms)  SELECT COUNT(*) FROM "microposts" WHERE "microposts"."user_id" = ?  [["user_id", 2]]
  Rendered users/show.html.erb within layouts/application (129.0ms)
  Rendered layouts/_rails_default.html.erb (59.2ms)
  Rendered layouts/_shim.html.erb (0.4ms)
  Rendered layouts/_header.html.erb (0.9ms)
  Rendered layouts/_footer.html.erb (1.2ms)
Completed 200 OK in 210ms (Views: 203.3ms | ActiveRecord: 1.3ms)
yutokyokutyo commented 7 years ago
  1. ブラウザから /users/2 にアクセスし、うまく動いているかどうか確認してみましょう。

ページ遷移ない。ok!

  1. 先ほどの演習で確認が終わったら、Railsサーバーのログを閲覧し、フォロー/フォロー解除を実行した直後のテンプレートがどうなっているか確認してみましょう。

ユーザーはプロフィールページを最初に表示し、それからユーザーをフォローし、その後すぐ元のページにリダイレクトされるという流れがなくなった。

フォロー

Started POST "/relationships" for 127.0.0.1 at 2017-05-15 12:38:09 +0900
Processing by RelationshipsController#create as JS
  Parameters: {"utf8"=>"✓", "followed_id"=>"2", "commit"=>"Follow"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   (0.0ms)  begin transaction
  CACHE (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  SQL (0.3ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 101], ["followed_id", 2], ["created_at", 2017-05-15 03:38:09 UTC], ["updated_at", 2017-05-15 03:38:09 UTC]]
   (1.8ms)  commit transaction
  Rendering relationships/create.js.erb
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 101], ["followed_id", 2], ["LIMIT", 1]]
  Rendered users/_unfollow.html.erb (2.0ms)
   (0.2ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 2]]
  Rendered relationships/create.js.erb (7.2ms)
Completed 200 OK in 25ms (Views: 11.7ms | ActiveRecord: 3.0ms)

フォロー解除

Started DELETE "/relationships/93" for 127.0.0.1 at 2017-05-15 12:38:33 +0900
Processing by RelationshipsController#destroy as JS
  Parameters: {"utf8"=>"✓", "commit"=>"Unfollow", "id"=>"93"}
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 101], ["LIMIT", 1]]
  Relationship Load (0.1ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."id" = ? LIMIT ?  [["id", 93], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  Relationship Load (0.4ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 101], ["followed_id", 2], ["LIMIT", 1]]
   (0.1ms)  begin transaction
  SQL (0.7ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 93]]
   (2.0ms)  commit transaction
  Rendering relationships/destroy.js.erb
  Rendered users/_follow.html.erb (1.8ms)
   (0.2ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 2]]
  Rendered relationships/destroy.js.erb (8.7ms)
Completed 200 OK in 54ms (Views: 12.9ms | ActiveRecord: 4.5ms)
yutokyokutyo commented 7 years ago
  1. リスト 14.36のrespond_toブロック内の各行を順にコメントアウトしていき、テストが正しくエラーを検知できるかどうか確認してみましょう。実際、どのテストケースが落ちたでしょうか?

format.html { redirect_to @user }

ERROR["test_should_follow_a_user_the_standard_way", FollowingTest, 0.9140365780003776]
 test_should_follow_a_user_the_standard_way#FollowingTest (0.91s)
ActionController::UnknownFormat:         ActionController::UnknownFormat: ActionController::UnknownFormat
            app/controllers/relationships_controller.rb:7:in `create'
            test/integration/following_test.rb:31:in `block (2 levels) in <class:FollowingTest>'
            test/integration/following_test.rb:30:in `block in <class:FollowingTest>'
  1. リスト 14.40のxhr: trueがある行のうち、片方のみを削除するとどういった結果になるでしょうか? このとき発生する問題の原因と、なぜ先ほどの演習で確認したテストがこの問題を検知できたのか考えてみてください。

再考..。

 FAIL["test_should_unfollow_a_user_with_Ajax", FollowingTest, 2.5183255889987777]
 test_should_unfollow_a_user_with_Ajax#FollowingTest (2.52s)
        "@user.following.count" didn't change by -1.
        Expected: 2
          Actual: 3
        test/integration/following_test.rb:52:in `block in <class:FollowingTest>'
yutokyokutyo commented 7 years ago

マイクロポストのidが正しく並んでいると仮定して (すなわち若いidの投稿ほど古くなる前提で)、図 14.22のデータセットでuser.feed.map(&:id)を実行すると、どのような結果が表示されるでしょうか? 考えてみてください。ヒント: 13.1.4で実装したdefault_scopeを思い出してください。

default_scope は desc で定義しているのでuser.feedのプライマリキーに対して降順で出力される。

yutokyokutyo commented 7 years ago

リスト 14.44において、現在のユーザー自身の投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?

% git diff                                                                                                                    (git)-[following-users]
diff --git a/app/models/user.rb b/app/models/user.rb
index 6ac811c..f9f55c0 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -80,7 +80,7 @@ class User < ApplicationRecord

   # ユーザーのステータスフィードを返す
   def feed
-    Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
+    Micropost.where("user_id IN (?)", following_ids)
   end
% rails t                                                                                                                     (git)-[following-users]
Running via Spring preloader in process 88624
Started with run options --seed 19590

 FAIL["test_feed_should_have_the_right_posts", UserTest, 3.5444060699956026]
 test_feed_should_have_the_right_posts#UserTest (3.54s)
        Expected false to be truthy.
        test/models/user_test.rb:109:in `block (2 levels) in <class:UserTest>'
        test/models/user_test.rb:108:in `block in <class:UserTest>'

 FAIL["test_micropost_interface", MicropostsInterfaceTest, 5.9652901719964575]
 test_micropost_interface#MicropostsInterfaceTest (5.97s)
        Expected at least 1 element matching "div.pagination", found 0..
        Expected 0 to be >= 1.
        test/integration/microposts_interface_test.rb:12:in `block in <class:MicropostsInterfaceTest>'

 FAIL["test_micropost_sidebar_count", MicropostsInterfaceTest, 6.097592590995191]
 test_micropost_sidebar_count#MicropostsInterfaceTest (6.10s)
        Expected /href="\/microposts/ to match "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Ruby on Rails Tutorial Sample App</title>\n    \n<link rel=\"stylesheet\" media=\"all\" href=\"/assets/application-079466ebcd4bce80971054d5b8fdeaeb00fad77a6daa7c6b6d2a5cb2297540a8.css\" data-turbolinks-track=\"reload\" />\n<script src=\"/assets/application-cdf2fab77c481df8193e0f9e5dd280d14e615345ac40d713b5809e989e46727d.js\" data-turbolinks-track=\"reload\"></script>\n\n    <!--[if lt IE 9]>\n  <script src=\"//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js\">\n  </script>\n<![endif]-->\n\n  </head>\n  <body>\n    <header class=\"navbar navbar-fixed-top navbar-inverse\">\n  <div class=\"container\">\n    <a id=\"logo\" href=\"/\">sample app</a>\n    <nav>\n      <ul class=\"nav navbar-nav navbar-right\">\n        <li><a href=\"/\">Home</a></li>\n        <li><a href=\"/help\">Help</a></li>\n          <li><a href=\"/users\">Users</a></li>\n          <li class=\"dropdown\">\n            <a href=\"#\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">\n              Account <b class=\"caret\"></b>\n            </a>\n            <ul class=\"dropdown-menu\">\n              <li><a href=\"/users/762146111\">Profile</a></li>\n              <li><a href=\"/users/762146111/edit\">Settings</a></li>\n              <li class=\"divider\"></li>\n              <li>\n                <a rel=\"nofollow\" data-method=\"delete\" href=\"/logout\">Log out</a>\n              </li>\n            </ul>\n          </li>\n      </ul>\n    </nav>\n  </div>\n</header>\n\n    <div class=\"container\">\n        <div class=\"row\">\n  <aside class=\"col-md-4\">\n    <section class=\"user_info\">\n      <a href=\"/users/762146111\"><img alt=\"Michael Example\" class=\"gravatar\" src=\"https://secure.gravatar.com/avatar/03ea78c0884c9ac0f73e6af7b9649e90?s=50\" /></a>\n<h1>Michael Example</h1>\n<span><a href=\"/users/762146111\">view my profile</a></span>\n<span>34 microposts</span>\n\n    </section>\n    <section class=\"stats\">\n      <div class=\"stats\">\n  <a href=\"/users/762146111/following\">\n    <strong id=\"following\" class=\"stat\">\n      2\n    </strong>\n    following\n  </a>\n  <a href=\"/users/762146111/followers\">\n    <strong id=\"followers\" class=\"stat\">\n      2\n    </strong>\n    followers\n  </a>\n</div>\n\n    </section>\n    <section class=\"micropost_form\">\n      <form class=\"new_micropost\" id=\"new_micropost\" enctype=\"multipart/form-data\" action=\"/microposts\" accept-charset=\"UTF-8\" method=\"post\"><input name=\"utf8\" type=\"hidden\" value=\"&#x2713;\" />\n  \n  <div class=\"field\">\n    <textarea placeholder=\"Compose new micropost...\" name=\"micropost[content]\" id=\"micropost_content\">\n</textarea>\n  </div>\n  <input type=\"submit\" name=\"commit\" value=\"Post\" class=\"btn btn-primary\" data-disable-with=\"Post\" />\n  <span class=\"picture\">\n    <input accept=\"image/jpeg,image/gif,image/png\" type=\"file\" name=\"micropost[picture]\" id=\"micropost_picture\" />\n  </span>\n</form>\n<script type=\"text/javascript\">\n  $('#micropost_picture').bind('change', function() {\n    var size_in_megabytes = this.files[0].size/1024/1024;\n    if (size_in_megabytes > 5) {\n      alert('Maximum file size is 5MB. Please choose a smaller file.');\n    }\n  });\n</script>\n\n    </section>\n  </aside>\n  <div class=\"col-md-8\">\n    <h3>Micropost Feed</h3>\n      <ol class=\"microposts\">\n    <li id=\"micropost-3454773\">\n  <a href=\"/users/409608538\"><img alt=\"Lana Kane\" class=\"gravatar\" src=\"https://secure.gravatar.com/avatar/de9a58df9617af487e8b28dbb3aa50de?s=50\" /></a>\n  <span class=\"user\"><a href=\"/users/409608538\">Lana Kane</a></span>\n  <span class=\"content\">\n    I&#39;m sorry. Your words made sense, but your sarcastic tone did not.\n    \n  </span>\n  <span class=\"timestamp\">\n    Posted 10 minutes ago.\n  </span>\n</li>\n<li id=\"micropost-970054474\">\n  <a href=\"/users/409608538\"><img alt=\"Lana Kane\" class=\"gravatar\" src=\"https://secure.gravatar.com/avatar/de9a58df9617af487e8b28dbb3aa50de?s=50\" /></a>\n  <span class=\"user\"><a href=\"/users/409608538\">Lana Kane</a></span>\n  <span class=\"content\">\n    Dude, this van&#39;s, like, rolling probable cause.\n    \n  </span>\n  <span class=\"timestamp\">\n    Posted about 4 hours ago.\n  </span>\n</li>\n\n  </ol>\n  \n\n  </div>\n</div>\n\n\n      <footer class=\"footer\">\n  <small>\n    The <a href=\"http://railstutorial.jp/\">Ruby on Rails Tutorial</a>\n    by <a href=\"http://www.michaelhartl.com/\">Michael Hartl</a>\n  </small>\n  <nav>\n    <ul>\n      <li><a href=\"/about\">About</a></li>\n      <li><a href=\"/contact\">Contact</a></li>\n      <li><a href=\"http://news.railstutorial.org/\">News</a></li>\n    </ul>\n  </nav>\n</footer>\n\n      \n    </div>\n  </body>\n</html>\n".
        test/integration/microposts_interface_test.rb:43:in `block in <class:MicropostsInterfaceTest>'

  73/73: [=======================================================================================================] 100% Time: 00:00:06, Time: 00:00:06

Finished in 6.93176s
73 tests, 330 assertions, 3 failures, 0 errors, 0 skips
yutokyokutyo commented 7 years ago

リスト 14.44において、フォローしているユーザーの投稿を含めないようにするにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか?

% git diff                                                                                                                    (git)-[following-users]
diff --git a/app/models/user.rb b/app/models/user.rb
index 6ac811c..a4c959a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -80,7 +80,7 @@ class User < ApplicationRecord

   # ユーザーのステータスフィードを返す
% rails t                                                                                                                     (git)-[following-users]
Running via Spring preloader in process 89247
Started with run options --seed 63652

 FAIL["test_feed_should_have_the_right_posts", UserTest, 6.306453445999068]
 test_feed_should_have_the_right_posts#UserTest (6.31s)
        Expected false to be truthy.
        test/models/user_test.rb:105:in `block (2 levels) in <class:UserTest>'
        test/models/user_test.rb:104:in `block in <class:UserTest>'

  73/73: [=======================================================================================================] 100% Time: 00:00:06, Time: 00:00:06

Finished in 6.87327s
73 tests, 343 assertions, 1 failures, 0 errors, 0 skips
yutokyokutyo commented 7 years ago

リスト 14.44において、フォローしていないユーザーの投稿を含めるためにはどうすれば良いでしょうか? また、そのような変更を加えると、リスト 14.42のどのテストが失敗するでしょうか? ヒント: 自分自身とフォローしているユーザー、そしてそれ以外という集合は、いったいどういった集合を表すのか考えてみてください。

% git diff                                                                                                                    (git)-[following-users]
diff --git a/app/models/user.rb b/app/models/user.rb
index 6ac811c..4a31ece 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -80,7 +80,7 @@ class User < ApplicationRecord

   # ユーザーのステータスフィードを返す
   def feed
-    Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
+    Micropost.where("user_id NOT IN (?) OR user_id = ?", following_ids, id)
   end

   # ユーザーをフォローする
[y.kondo@PMAC359S] ~/project/workspace/rebuild_sample_app
% rails t                                                                                                                     (git)-[following-users]
Running via Spring preloader in process 94035
Started with run options --seed 2105

 FAIL["test_feed_should_have_the_right_posts", UserTest, 6.917525805998594]
 test_feed_should_have_the_right_posts#UserTest (6.92s)
        Expected false to be truthy.
        test/models/user_test.rb:105:in `block (2 levels) in <class:UserTest>'
        test/models/user_test.rb:104:in `block in <class:UserTest>'

  73/73: [=======================================================================================================] 100% Time: 00:00:07, Time: 00:00:07

Finished in 7.20998s
73 tests, 343 assertions, 1 failures, 0 errors, 0 skips
yutokyokutyo commented 7 years ago
  1. Homeページで表示される1ページ目のフィードに対して、統合テストを書いてみましょう。リスト 14.49はそのテンプレートです。

https://github.com/yutokyokutyo/rebuild_sample_app/commit/b4f19153abca098abb65a7b0ad45ef771c0a2533

  1. リスト 14.49のコードでは、期待されるHTMLをCGI.escapeHTMLメソッドでエスケープしています (このメソッドは11.2.3で扱ったCGI.escapeと同じ用途です)。このコードでは、なぜHTMLをエスケープさせる必要があったのでしょうか? 考えてみてください。ヒント: 試しにエスケープ処理を外して、得られるHTMLの内容を注意深く調べてください。マイクロポストの内容が何かおかしいはずです。また、ターミナルの検索機能 (Cmd-FもしくはCtrl-F) を使って「sorry」を探すと原因の究明に役立つはずです。
yutokyokutyo commented 7 years ago

良さそう。 http://morizyun.github.io/blog/ruby-rails-non-beginner-guide-book/

yutokyokutyo commented 7 years ago

完! chico

yutokyokutyo commented 7 years ago

今後に期待! o0400030012656494473