railsチュートリアル第十四章 フォローしているユーザー

###フォローしているユーザー
####Userモデルにfollowingの関連付けを追加する
app/models/user.rb

```rb
class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  # 他のモデルとの間に「1対多」のつながり
  # has_many関連付けが使われている場合、
  #   「反対側」のモデルでは多くの場合belongs_toが使われます。
  # dependent: :destroy
  # ユーザーが破棄された場合
  #   、ユーザーのマイクロポストも同様に破棄される。
  has_many :active_relationships, class_name:  "Relationship",
  # :active_relationsshitpsデータモデル 能動的関係(フォローしているがフォローはされていない関係)
  # class_name: テーブル名 "Relationship"
                                  foreign_key: "follower_id",
                                  # foreign_key: 外部キー
                                  #   データベースの二つのテーブルを繋げる
                                  # Micropostモデルとrelationshipsモデルを繋げる
                                  dependent:   :destroy
                                  # ユーザーが削除されるとマイクロポストも削除される
  has_many :following, through: :active_relationships, source: :followed
  # :following followingデータモデル 
  # has_many :through関連付けは、他方のモデルと「多対多」のつながりを設定する場合によく使われます。
  # この関連付けは、2つのモデルの間に「第3のモデル」(joinモデル)が介在する点が特徴です。
  # フォローするには:active_relationshipsデータモデルが介在する
  # source: following配列の元はfollowed idの集合である
.
.
.
end
```

###“following” 関連のメソッドをテストする 
test/models/user_test.rb

```rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase
  def setup
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: "foobar", password_confirmation: "foobar")
  end
.
.
.
  test "should follow and unfollow a user" do
    michael = users(:michael)
    # テストユーザーを代入
    archer  = users(:archer)
    assert_not michael.following?(archer)
    # archerはmichaelをふぉろーしていないことを確認
    michael.follow(archer)
    # archerをフォロー
    assert michael.following?(archer)
    # フォローしているか？
    michael.unfollow(archer)
    assert_not michael.following?(archer)
  end
end
```

###"following" 関連のメソッド 
app/models/user.rb

```rb
class User < ApplicationRecord
.
.
.
   # ユーザーをフォローする
  def follow(other_user)
    following << other_user
    # followingは配列になっている
    # << 指定された obj を自身の末尾に破壊的に追加します。
    # following配列にothe_userを破壊的に追加させる
  end

  # ユーザーをフォロー解除する
  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
    # active_relationshiipsデータモデルからフォロワーをidを探す
    # それを削除する
  end

  # 現在のユーザーがフォローしてたらtrueを返す
  def following?(other_user)
    following.include?(other_user)
    # followingデータモデル
    # 引数(othe r_user)を配列の名から探す
    # それがあればtureを返す。
  end

  private
.
.
.
end
```

#####テスト
```
ubuntu:~/environment/sample_app (following-users) $ rails t
Running via Spring preloader in process 5103
Started with run options --seed 54684

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

Finished in 7.01682s
63 tests, 319 assertions, 0 failures, 0 errors, 0 skips
```

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

```rb
>> michael.follow(archer)
   (0.1ms)  begin transaction
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Relationship Create (1.6ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", "2021-10-28 12:59:26.258244"], ["updated_at", "2021-10-28 12:59:26.258244"]]
   (0.1ms)  rollback transaction
Traceback (most recent call last):
        3: from (irb):5
        2: from (irb):5:in `rescue in irb_binding'
        1: from app/models/user.rb:135:in `follow'
ActiveRecord::RecordNotUnique (SQLite3::ConstraintException: UNIQUE constraint failed: relationships.follower_id, relationships.followed_id)
>> 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

>> michael.follow(archer)
   (0.1ms)  begin transaction
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Relationship Create (0.6ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", "2021-10-28 13:00:30.403974"], ["updated_at", "2021-10-28 13:00:30.403974"]]
   (0.1ms)  rollback transaction
Traceback (most recent call last):
        2: from (irb):7
        1: from app/models/user.rb:135:in `follow'
ActiveRecord::RecordNotUnique (SQLite3::ConstraintException: UNIQUE constraint failed: relationships.follower_id, relationships.followed_id)
# 一意性がないらしい 

>> 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

>> 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.0ms)  begin transaction
  Relationship Destroy (6.1ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 1]]
   (7.7ms)  commit transaction
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2021-10-28 06:05:06", updated_at: "2021-10-28 06:05:06">

>> 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
```

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

```
SELECT 1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ? 

 SELECT "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ? 

 SELECT 1 AS one FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."followed_id" WHERE "relationships"."follower_id" = ? AND "users"."id" = ? LIMIT ? 
```

わからない。