【Railsチュートリアル】第14章 ユーザーをフォローする②

# 14.2 ［Follow］のWebインターフェイス

* フォロー/フォロー解除の基本的なインターフェイスを実装する
* フォローしているユーザーと、フォロワーにそれぞれ表示用のページを作成する


## 14.2.1 フォローのサンプルデータ

### 演習 1
コンソールを開き、User.first.followers.countの結果がリスト 14.14で期待している結果と合致していることを確認してみましょう。

```ruby
>> User.first.followers.count
   (2.2ms)  SELECT sqlite_version(*)
  User Load (2.1ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
   (2.5ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> 38
```

### 演習 2
先ほどの演習と同様に、User.first.following.countの結果も合致していることを確認してみましょう。

```ruby
>> User.first.following.count
  User Load (2.0ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
   (2.5ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ?  [["follower_id", 1]]
=> 49
```

## 14.2.2 統計と［Follow］フォーム
* プロフィールページとHomeページを更新して、これを反映する

```ruby:config/routes.rb
.
.
.
resources :users do
    member do
      get :following, :followers
      # GET /users/1/following
      # GET /users/1/followiers
    end
  end
.
.
.
```

```ruby:app/views/shared/_stats.html.erb
<% @user ||= current_user %>
  <%# @userがnilではない場合、@userにcurrent_userを代入する %>
<div class="stats">
  <a href="<%= following_user_path(@user) %>">
    <strong id="following" class="stat">
      <%= @user.following.count %>
    </strong>
    following
  </a>
  <a href="<%= followers_user_path(@user) %>">
    <strong id="followers" class="stat">
      <%= @user.followers.count %>
    </strong>
    followers
  </a>
</div>
```

```ruby:app/views/users/_follow_form.html.erb
<% unless current_user?(@user) %>
  <%# current_user == @userでなければ %>
  <div id="follow_form">
  <% if current_user.following?(@user) %>
    <%= render 'unfollow' %>
  <% else %>
    <%= render 'follow' %>
  <% end %>
  </div>
<% end %>
```

### 演習 1
ブラウザから /users/2 にアクセスし、フォローボタンが表示されていることを確認してみましょう。同様に、/users/5 では［Unfollow］ボタンが表示されているはずです。さて、/users/1 にアクセスすると、どのような結果が表示されるでしょうか?

Followボタン、　Unfollowボタン自体が無い

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

確認のみなので省略

### 演習 3
Homeページに表示されている統計情報に対してテストを書いてみましょう。ヒント: リスト 13.28で示したテストに追加してみてください。同様にして、プロフィールページにもテストを追加してみましょう。

```ruby:test/integration/site_layout_test.rb
require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest
.
.
.
test "layout links when loged in" do
    log_in_as(@user)
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", users_path
    assert_select "a[href=?]", user_path(@user)
    assert_select "a[href=?]", edit_user_path(@user)
    assert_select "a[href=?]", logout_path
    assert_select "strong#following"
      # <strong id="following">があるか
    assert_match @user.following.count.to_s, response.body
      # <body>に@user.following.countを文字列にしたものがあるか
    assert_select "strong#followers"
      # <strong id="following">があるか
    assert_match @user.followers.count.to_s, response.body
      # <body>に@user.followers.countを文字列にしたものがあるか
  end
end
```

```ruby:test/integration/user_profile_test.rb

require 'test_helper'

class UsersProfileTest < ActionDispatch::IntegrationTest
  include ApplicationHelper

  def setup
    @user = users(:michael)
  end

  test "profile display" do
    get user_path(@user)
    assert_template 'users/show'
    assert_select 'title', full_title(@user.name)
    assert_select 'h1', text: @user.name
    assert_select 'h1>img.gravatar'
    assert_select "strong#following"
    # <strong id="following">があるか
    assert_match @user.following.count.to_s, response.body
    # <body>に@user.following.countを文字列にしたものがあるか
    assert_select "strong#followers"
    # <strong id="following">があるか
    assert_match @user.followers.count.to_s, response.body
    # <body>に@user.followers.countを文字列にしたものがあるか
    assert_match @user.microposts.count.to_s, response.body
    assert_select 'div.pagination', count: 1
    @user.microposts.paginate(page: 1).each do |micropost|
      assert_match micropost.content, response.body
    end

  end
end
```

## 14.2.3 ［Following］と［Followers］ページ

```ruby:test/integration/following_test.rb
require 'test_helper'

class FollowingTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
    log_in_as(@user)
      # michaelでログイン
  end

  test "following page" do
    get following_user_path(@user)
      # followingページにアクセス
    assert_not @user.following.empty?
      # フォローしているはず
    assert_match @user.following.count.to_s, response.body
      # <body>にフォロー数が表示されているはず
    @user.following.each do |user|
      assert_select "a[href=?]", user_path(user)
        # フォローのリンクがあるはず
    end
  end

  test "followers page" do
    get followers_user_path(@user)
      # followersページにアクセス
    assert_not @user.followers.empty?
      # フォロワーがいるはず
    assert_match @user.followers.count.to_s, response.body
      # <body>にフォロワー数が表示されているはず
    @user.followers.each do |user|
      assert_select "a[href=?]", user_path(user)
        # フォロワーのリンクがあるはず
    end
  end
end
```

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

確認だけなので省略。

### 演習 2
リスト 14.29のassert_selectに関連するコードをコメントアウトしてみて、テストが正しく red に変わることを確認してみましょう。

確認のみなので省略。

## 14.2.4 ［Follow］ボタン（基本編）
### 演習 1
ブラウザ上から /users/2 を開き、［Follow］と［Unfollow］を実行してみましょう。うまく機能しているでしょうか?

うまく機能していました。

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

```ruby:Unfollow
Relationship Destroy (13.6ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 88]]
```

```ruby:Follow
 Relationship Create (9.9ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 3], ["created_at", "2021-03-21 12:05:09.044437"], ["updated_at", "2021-03-21 12:05:09.044437"]]
```

## 14.2.5 ［Follow］ボタン（Ajax編）
* Ajaxを使って非同期（ページを移動せずに）でリクエストを送信する

### 演習 1
ブラウザから /users/2 にアクセスし、うまく動いているかどうか確認してみましょう。

うまく動いていました。

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

Unfollow→Follow
Rendered relationships/create.js.erb

Follow→Unfollow
Rendered relationships/destroy.js.erb

## 14.2.6 フォローをテストする
* バグを検知するためのシンプルなテストを書いていく

### 演習 1
リスト 14.36のrespond_toブロック内の各行を順にコメントアウトしていき、テストが正しくエラーを検知できるかどうか確認してみましょう。実際、どのテストケースが落ちたでしょうか?

`format.html { redirect_to @user }`は落ちる。
`format.js`は落ちない。


### 演習 2
リスト 14.40のxhr: trueがある行のうち、片方のみを削除するとどういった結果になるでしょうか? このとき発生する問題の原因と、なぜ先ほどの演習で確認したテストがこの問題を検知できたのか考えてみてください。

```ruby
test "should follow a user with Ajax" do
  assert_difference '@user.following.count', 1 do
    # post relationships_path, xhr: true, params: { followed_id: @other.id }
  end
end


FAIL["test_should_follow_a_user_with_Ajax", #<Minitest::Reporters::Suite:0x00007f5a9ffae870 @name="FollowingTest">, 4.709730960999991]
 test_should_follow_a_user_with_Ajax#FollowingTest (4.71s)
        "@user.following.count" didn't change by 1.
        Expected: 3
          Actual: 2
        test/integration/following_test.rb:46:in `block in <class:FollowingTest>'
```


ブロック内で何も処理が行われておらず`@user.following.count`に変化がないためにエラーが起こる。