Railsチュートリアル 第14章

14.1 Relationshipモデル

14.1.1

マイグレーションした際にschema.rbに反映されませんでした. しかしバッファにはなんのエラーも出ませんでした. ちょっと調べてみましょう.

以下のコマンドでデータベースに接続できます.

$ rails db

私のようにDockerで環境構築している場合は次のようになるでしょう. ちなみに私はMySQLRailsとは別のコンテナで起動させています.

$ docker-compose exec web rails db

するとパスワードが求められるので, database.ymlで指定したパスワードを入力します. すると以下のようなプロンプトが表示されます.

MySQL [myapp_development]>

myapp_developmentはデータベース名ですね. マイグレーションしたテーブルが存在するかを確認してみます.

MySQL [myapp_development]> show tables;
+-----------------------------+
| Tables_in_myapp_development |
+-----------------------------+
| ar_internal_metadata        |
| microposts                  |
| relationships               |
| schema_migrations           |
| users                       |
+-----------------------------+
5 rows in set (0.01 sec)

しかしschema.rbに反映されていないのはおかしいので, マイグレーションをやりなおしましょう.

MySQL [myapp_development]> exit
Bye
$ docker-compose exec web rails db:rollback
$ docker-compose exec web rails db:migrate

すると以下のようなエラーが出ました.

Mysql2::Error: Table 'relationships' already exists

そもそも最初のマイグレーションがうまくいってないから, ロールバックによってテーブルが削除されなかったようですね. では手動でテーブルを削除しましょう.

$ docker-compose exec web rails db
MySQL [myapp_development]> drop table relationships;
Query OK, 0 rows affected (0.02 sec)
MySQL [myapp_development]> exit
Bye

ここでもう一度マイグレーションをしたところ, ちゃんとschema.rbに反映されました.

演習1

答えが問題文中に書かれていますね. 図14.7を見ると以下の配列が得られることがわかります.

[2, 7, 10, 8]

演習2

idが2であるユーザーはidが1のユーザーしかフォローしていません. したがってこのユーザーだけからなる配列が得られます.

したがってuser.followind.map(&:id)[1]に等しいですね.

14.1.2

演習1, 2

省略.

14.1.3

演習1

たしかにバリデーションを解除してもテストは成功しました.

14.1.4

演習1, 2

以下の通りです.

>> first = User.first
>> second = User.second

>> first.following?(second)
    SELECT  1 AS one FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1 AND `users`.`id` = 2 LIMIT 1
=> false

>> first.follow(second)
    INSERT INTO `relationships` (`follower_id`, `followed_id`, `created_at`, `updated_at`) VALUES (1, 2, '2018-07-05 15:19:20', '2018-07-05 15:19:20')

>> first.following?(second)
=> true

>> first.unfollow(second)
    DELETE FROM `relationships` WHERE `relationships`.`id` = 1

>> first.following?(second)
=> false

14.1.5

演習1

>> user = User.first
>> second = User.second
>> last = User.last

>> second.follow(user)
>> last.follow(user)

>> user.followers.map(&:id)
    SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`follower_id` WHERE `relationships`.`followed_id` = 1
=> [2, 100]

演習2, 3

前者はデータベースの中で数えていますが, 後者はRubyの配列として数えています. したがって前者のほうがパフォーマンスが高いですね.

user.followers.count
    SELECT COUNT(*) FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`follower_id` WHERE `relationships`.`followed_id` = 1
=> 2

>> user.followers.to_a.count
=> 2

14.2 [follow]のWebインターフェース

14.2.1

演習1, 2

>> user = User.first
>> user.following.count
=> 49
>> user.followers.count
=> 38

14.2.2

演習1, 2

省略.

演習3

プロフィールテストに書きました.

# test/integration/users_profile_test.rb

test "stats" do
    log_in_as(@user)
    get root_path
    assert_select '#following', text: "#{@user.following.count}"
    assert_select '#followers', text: "#{@user.followers.count}"

    get user_path(@user)
    assert_select '#following', text: "#{@user.following.count}"
    assert_select '#followers', text: "#{@user.followers.count}"
end

以下のように数字のままだとダメでした.

assert_select '#following', text: @user.following.count

14.2.3

演習1, 2

省略.

14.2.4

演習1

省略.

演習2

Follow, Unfollowどちらを押しても, users/showが描画されています.

Rendered users/show.html.erb within layouts/application

14.2.5

演習1

Safariの開発メニューからJavascriptを無効にした場合もちゃんと動作しました.

演習2

省略.

14.2.6

演習1, 2

省略.

14.3 ステータスフィード

14.3.1

演習1

新しい順に取得するので, 以下のようになるでしょう.

user.feed.map(&:id)
=> [10, 9, 7, 5, 4, 2, 1]

14.3.2

演習1

feedメソッドを以下のように変更すればいいですね.

def feed
    Micropost.where("user_id IN (?)", following_ids)
end

この場合はmichael自身の投稿を確認するテストで失敗します.

演習2

これは13章で実装した通りですね.

def feed
    Micropost.where("user_id = ?", id)
end

するとlanaの投稿を確認するテストで失敗します.

演習3

feedメソッドを以下のように変更すればいいですね.

def feed
    Micropost.all
end

するとarcherの投稿を確認するテストで失敗します.

14.3.3

演習1

以下の通りです.

test "feed on Home page" do
    get root_path
    @user.feed.paginate(page: 1) do |micropost|
        assert_match CGI.escapeHTML(micropost.content), response.body
    end
end

演習2

ヒントから, 以下のmicropostがまずいんでしょうが, よくわかりませんでした.

tone:
  content: "I'm sorry. Your words made sense, but your sarcastic tone did not."
  created_at: <%= 10.minutes.ago %>
  user: lana