35歳だけどRailsチュートリアルやってみた。[第4版 14章 14.1 Relationshipモデル まとめ&解答例]

#はじめに
最近、プロジェクト管理業務が業務の大半を占めており、
プログラムを書く機会がなかなかありません。

このままだとプログラムがまったく書けない人になってしまう危機感（迫り来る35歳定年説）と、
新しいことに挑戦したいという思いから、
[Ruby on Rails チュートリアル実例を使ってRailsを学ぼう 第4版](https://railstutorial.jp/)を学習中です。
業務で使うのはもっぱらJavaなのですが、Rails楽しいですね。


これまでEvernoteに記録していましたが、ソースコードの貼付けに限界を感じたため、
Qiitaで自分が学習した結果をアウトプットしていきます。

個人の解答例なので、誤りがあればご指摘ください。

##動作環境
- cloud9
- ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
- Rails 5.0.0.1

##14.1.1 データモデルの問題 (および解決策)
###本章での学び

####【DB設計】各モデルの考え方
ユーザー、ユーザーがフォローしているユーザー、能動的関係の３つを設計する。

ユーザー：userテーブル
ユーザーがフォローしているユーザー:user.following（userテーブルの集合）
能動的関係：active_relationshipsテーブル

![image](https://qiita-image-store.s3.amazonaws.com/0/98130/080e59aa-05bf-3908-ce56-c491eed947d4.png)

- 自分からフォローする（能動的関係）
- 相手からフォローされる（受動的関係）

どちらも１つのテーブルで実現するため、テーブル名は`relationships`テーブルとなる。

![image](https://qiita-image-store.s3.amazonaws.com/0/98130/da23818f-9df0-5c2f-a4ff-efc8d014ace9.png)

上記を踏まえ、実装する。

```
```

####【DB】マイグレーションファイルの作成
`rails generate`で、relationshipsテーブルの
マイグレーションファイルを自動生成する。

```irb
yokoyan:~/workspace/sample_app (following-users) $ rails generate model Relationship follower_id:integer followed_id:integer
^[Running via Spring preloader in process 3357
Expected string default value for '--jbuilder'; got true (boolean)
      invoke  active_record
      create    db/migrate/20170823121831_create_relationships.rb
      create    app/models/relationship.rb
      invoke    test_unit
      create      test/models/relationship_test.rb
      create      test/fixtures/relationships.yml
```

####【DB】マイグレーションファイルにインデックスを追加
自動生成したマイグレーションファイルに、インデックスを追加する。
`[:follower_id, :followed_id], unique: true`は複合キー。
2つのidの組み合わせが必ずユニークであることを保証する。
（同じユーザーを２回以上フォローできないようにする）

```/sample_app/db/migrate/20170823121831_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.0]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :followed_id

      t.timestamps
    end
    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true
  end
end
```

####【DB】マイグレーションの実行
relationshipsテーブルを作成する。

```irb
yokoyan:~/workspace/sample_app (following-users) $ rails db:migrate
== 20170823121831 CreateRelationships: migrating ==============================
-- create_table(:relationships)
   -> 0.0094s
== 20170823121831 CreateRelationships: migrated (0.0095s) =====================
```

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

id=1がフォローしているユーザーの配列が取得できる。
(id=2,7,8,10のユーザー配列が取得できる）

###演習2
*図 14.7を参考にして、id=2のユーザーに対してuser.followingを実行すると、結果はどのようになるでしょうか? また、同じユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。*

id=2のユーザーは既にフォローしているのでフォローできない（またはフォローが解除される）
id=1がフォローしているユーザーの配列が取得できる。

##14.1.2 User/Relationshipの関連付け
###本章での学び

####【model】能動的関係に対して１対多（has_many）の関連付けを実装する
userモデルをリファクタリングする。
userモデルとrelationshipsモデルは１対多の関係となる。
能動的関係であることを示すために、`has_many :active_relationship`と名前をつけている。
明示的にクラス名と、外部キーの名称を指定している。

また、userを削除した場合、user間のrelationshipも削除されるように、
`dependent :destroy`を付与している。

```/sample_app/app/models/user.rb
class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  has_many :active_relationships, class_name: "Relationship",
                                  foreign_key: "follower_id",
                                  dependent: :destroy
```

####【model】リレーションシップ/フォロワーに対してbelongs_toの関連付けを追加する
relationshipモデルと、フォローされているuserモデル（またはフォローしているuserモデル）は１対１となるため、`belongs_to`で関連付けを行う。

```/sample_app/app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
end
```

####今回使えるようになったメソッド
![image](https://qiita-image-store.s3.amazonaws.com/0/98130/6417712e-6e73-e8b1-cff5-205e13612ee4.png)

###演習1
*コンソールを開き、表 14.1のcreateメソッドを使ってActiveRelationshipを作ってみましょう。データベース上に２人以上のユーザーを用意し、最初のユーザーが２人目のユーザーをフォローしている状態を作ってみてください。*

最初のユーザーが2人目のユーザーをフォローする。

```irb
yokoyan:~/workspace/sample_app (following-users) $ rails console --sandbox
Running via Spring preloader in process 2424
Loading development environment in sandbox (Rails 5.0.0.1)
Any modifications you make will be rolled back on exit
>> user = User.first
  User Load (0.5ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-07-26 21:31:59", updated_at: "2017-07-26 21:31:59", password_digest: "$2a$10$hr3puKUHMOdKoV.IkakM0uxzu3mOW./qM63oJ6Xq3q9...", remember_digest: nil, admin: true, activation_digest: "$2a$10$g6M8JTC1B48HIxzpi6iy8.qBKbQsxyaRos1ldkd2q9n...", activated: true, activated_at: "2017-07-26 21:31:59", reset_digest: nil, reset_sent_at: nil>
>> 
?> other_user = User.second
  User Load (0.4ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Chester Greenfelder III", email: "example-1@railstutorial.org", created_at: "2017-07-26 21:32:00", updated_at: "2017-07-26 21:32:00", password_digest: "$2a$10$OEftiG18yO2djfYF/Qd2yODa4aYbgFbLpgWRhX9zw/....", remember_digest: nil, admin: false, activation_digest: "$2a$10$tnRwE2WFuUJiQ4BlKEXbne1h2Ejr.8LrUPA7FY.WQMw...", activated: true, activated_at: "2017-07-26 21:32:00", reset_digest: nil, reset_sent_at: nil>
>> 
?> active_relationship = user.active_relationships.create(followed_id: other_user.id)
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.3ms)  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.5ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", 2017-08-24 10:52:28 UTC], ["updated_at", 2017-08-24 10:52:28 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2017-08-24 10:52:28", updated_at: "2017-08-24 10:52:28">
```

###演習2
*先ほどの演習を終えたら、active_relationship.followedの値とactive_relationship.followerの値を確認し、それぞれの値が正しいことを確認してみましょう。*

`active_relationship.followed`は、自分がフォローしているユーザを返す。
つまり、user_id=1のユーザが、user_id=2のユーザをフォローしているので、`User id:2`が返ってくる。

`active_relationship.follower`は、フォロワーを返す。
つまり、user_id=2のユーザのフォロワーである、`User id:1`が返ってくる。

```irb
?> active_relationship.followed
=> #<User id: 2, name: "Chester Greenfelder III", email: "example-1@railstutorial.org", created_at: "2017-07-26 21:32:00", updated_at: "2017-07-26 21:32:00", password_digest: "$2a$10$OEftiG18yO2djfYF/Qd2yODa4aYbgFbLpgWRhX9zw/....", remember_digest: nil, admin: false, activation_digest: "$2a$10$tnRwE2WFuUJiQ4BlKEXbne1h2Ejr.8LrUPA7FY.WQMw...", activated: true, activated_at: "2017-07-26 21:32:00", reset_digest: nil, reset_sent_at: nil>
>> 
?> active_relationship.follower
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-07-26 21:31:59", updated_at: "2017-07-26 21:31:59", password_digest: "$2a$10$hr3puKUHMOdKoV.IkakM0uxzu3mOW./qM63oJ6Xq3q9...", remember_digest: nil, admin: true, activation_digest: "$2a$10$g6M8JTC1B48HIxzpi6iy8.qBKbQsxyaRos1ldkd2q9n...", activated: true, activated_at: "2017-07-26 21:31:59", reset_digest: nil, reset_sent_at: nil>
```

##14.1.3 Relationshipのバリデーション
###本章での学び

####【test】Relationshipモデルのバリデーション
- setup
    - Relationshipモデルを生成する（followed_id: michael,follower_id: archer)
    - インスタンス変数@relationshipに代入する

- should be valid
    - @relationshipが有効であること

- should require a follower_id
    - @relationshipのfollower_idにnilを代入
    - @relationshipが有効ではないこと

- should require a followed_id
    - @relationshipのfollowed_idにnilを代入
    - @relationshipが有効ではないこと

上記を踏まえて実装する。

```/sample_app/test/models/relationship_test.rb
  test "should be valid" do
    assert @relationship.valid?
  end

  test "should require a follower_id" do
    @relationship.follower_id = nil
    assert_not @relationship.valid?
  end

  test "should require a followed_id" do
    @relationship.followed_id = nil
    assert_not @relationship.valid?
  end
```

####【model】 Relationshipモデルに対してバリデーションを追加する

```/sample_app/app/models/relationship.rb
  validates :follower_id, presence: true
  validates :followed_id, presence: true
```

####【fixture】Relationship用のfixtureを空にする
自動生成されたfixtureでは、Relationshipモデルの複合キーの一意性を満たせないため、
コメントアウトする。

```/sample_app/test/fixtures/relationships.yml
# one:
#   follower_id: 1
#   followed_id: 1

# two:
#   follower_id: 1
#   followed_id: 1
```

###演習1
*リスト 14.5のバリデーションをコメントアウトしても、テストが成功したままになっていることを確認してみましょう。(以前のRailsのバージョンでは、このバリデーションが必須でしたが、Rails 5から必須ではなくなりました。今回はフォロー機能の実装を優先しますが、この手のバリデーションが省略されている可能性があることを頭の片隅で覚えておくと良いでしょう。)*

該当箇所をコメントアウトする。

```/sample_app/app/models/relationship.rb
  # validates :follower_id, presence: true
  # validates :followed_id, presence: true
```

コメントアウトしてもテスト結果がgreenになることを確認。


##14.1.4 フォローしているユーザー
###本章での学び

####【model】 Userモデルにfollowingの関連付けを追加
多対多の関係性を表すために、`has_many through`を使う。
Railsは、デフォルトでは、has_manyに指定された単数形のモデル名に対応する外部キーを探す。
そのため、`:source`パラメータを使って、「following配列の元はfollowed_idの集合である」ことを明示的にする。

```/sample_app/app/models/user.rb
  has_many :following, through: :active_relationships, source: :followed
```

####【test】following関連のメソッドのテスト
- should follow and unfollow a user
    - fixtureからmichaelユーザ情報を取得
    - fixtureからarcherユーザ情報を取得
    - michaelが、archerをフォローしていないことを確認
    - michaelが、archerをフォローする
    - michaelが、archerをフォローしていることを確認
    - michaelが、archerをフォロー解除する
    - michaelが、archerをフォローしていないことを確認

上記を踏まえて実装する。

```/sample_app/test/models/user_test.rb
  test "should follow and unfollow a user" do
    michael = users(:michael)
    archer = users(:archer)
    assert_not michael.following?(archer)
    michael.follow(archer)
    assert michael.following?(archer)
    michael.unfollow(archer)
    assert_not michael.following?(archer)
  end
```

####【model】following関連のメソッドの実装
テストコードで作成したメソッドの中身を実装する。

```/sample_app/app/models/user.rb
  # ユーザーをフォローする
  def follow(other_user)
    active_relationships.create(followed_id: other_user.id)
  end

  # ユーザーをフォロー解除する
  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

  # 現在のユーザーがフォローしていたらtrueを返す
  def following?(other_user)
    following.include?(other_user)
  end
```

####テスト実行
テスト結果がgreenになることを確認。

```irb
yokoyan:~/workspace/sample_app (following-users) $ rails test
Running via Spring preloader in process 3177
Started with run options --seed 22441

DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only                                                       ] 9% Time: 00:00:01,  ETA: 00:00:16
the following keyword arguments in future Rails versions:
params, headers, env, xhr, as

Examples:

get '/profile',
  params: { id: 1 },
  headers: { 'X-Extra-Header' => '123' },
  env: { 'action_dispatch.custom' => 'custom' },
  xhr: true,
  as: :json
 (called from block (2 levels) in <class:MicropostsInterfaceTest> at /home/ubuntu/workspace/sample_app/test/integration/microposts_interface_test.rb:27)
  63/63: [=====================================================================================================================================] 100% Time: 00:00:03, Time: 00:00:03

Finished in 3.80719s
63 tests, 268 assertions, 0 failures, 0 errors, 0 skips
```

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

実行結果は以下の通り。

```irb
yokoyan:~/workspace/sample_app (following-users) $ rails console --sandbox
Running via Spring preloader in process 4373
Loading development environment in sandbox (Rails 5.0.0.1)
Any modifications you make will be rolled back on exit
>>
?> michael = User.first
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-07-26 21:31:59", updated_at: "2017-07-26 21:31:59", password_digest: "$2a$10$hr3puKUHMOdKoV.IkakM0uxzu3mOW./qM63oJ6Xq3q9...", remember_digest: nil, admin: true, activation_digest: "$2a$10$g6M8JTC1B48HIxzpi6iy8.qBKbQsxyaRos1ldkd2q9n...", activated: true, activated_at: "2017-07-26 21:31:59", reset_digest: nil, reset_sent_at: nil>
>>
?> archer = User.second
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Chester Greenfelder III", email: "example-1@railstutorial.org", created_at: "2017-07-26 21:32:00", updated_at: "2017-07-26 21:32:00", password_digest: "$2a$10$OEftiG18yO2djfYF/Qd2yODa4aYbgFbLpgWRhX9zw/....", remember_digest: nil, admin: false, activation_digest: "$2a$10$tnRwE2WFuUJiQ4BlKEXbne1h2Ejr.8LrUPA7FY.WQMw...", activated: true, activated_at: "2017-07-26 21:32:00", reset_digest: nil, reset_sent_at: nil>
>>
?> michael.following?(archer)
  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", 1], ["id", 2], ["LIMIT", 1]]
=> false
>>
?> michael.follow(archer)
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.4ms)  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 (2.0ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 1], ["followed_id", 2], ["created_at", 2017-08-26 00:55:42 UTC], ["updated_at", 2017-08-26 00:55:42 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2017-08-26 00:55:42", updated_at: "2017-08-26 00:55:42">
>> 
?> michael.following?(archer)
  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", 1], ["id", 2], ["LIMIT", 1]]
=> true
>> 
?> michael.unfollow(archer)
  Relationship Load (0.3ms)  SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = ? AND "relationships"."followed_id" = ? LIMIT ?  [["follower_id", 1], ["followed_id", 2], ["LIMIT", 1]]
   (0.1ms)  SAVEPOINT active_record_1
  SQL (0.4ms)  DELETE FROM "relationships" WHERE "relationships"."id" = ?  [["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 1, followed_id: 2, created_at: "2017-08-26 00:55:42", updated_at: "2017-08-26 00:55:42">
>> 
?> 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が出力されたのか確認してみましょう。*
演習1の結果参照。

##14.1.5 フォロワー
###本章での学び
フォロワー機能を実装する。

####【model】受動的関係のデータモデルの考え方
relationshipsテーブルを使う。
Michael（id=1）は、3人のユーザのにフォローされている。（id=3,2,9）
`followed_id=1`と、`follower_id=3,2,9`

![image](https://qiita-image-store.s3.amazonaws.com/0/98130/75ad5370-e34b-27e1-4258-bcbcc6d949d4.png)

上記を踏まえて実装する。

`source: :follower`を省略することも可能。
`has_many :followers`と記述した場合、Railsは自動的にfollowersを
単数形のfollowerに変換して、follower_idを探してくれる。

今回は、`has_many :following`との類似性を強調するために、
あえて記述している。

```/sample_app/app/models/user.rb
class User < ApplicationRecord
  has_many :microposts, dependent: :destroy
  has_many :active_relationships, class_name: "Relationship",
                                  foreign_key: "follower_id",
                                  dependent: :destroy
  has_many :passive_relationships, class_name: "Relationship",
                                  foreign_key: "followed_id",
                                  dependent: :destroy
  has_many :following, through: :active_relationships, source: :followed
  has_many :followers, through: :passive_relationships, source: :follower
```

####【test】followersに対するテスト

- should follow and unfollow a user
    - fixtureからmichaelユーザ情報を取得
    - fixtureからarcherユーザ情報を取得
    - michaelが、archerをフォローしていないことを確認
    - michaelが、archerをフォローする
    - michaelが、archerをフォローしていることを確認
    - archerのフォロワーに、michaelが存在することを確認
    - michaelが、archerをフォロー解除する
    - michaelが、archerをフォローしていないことを確認

上記を踏まえて実装する。

```/sample_app/test/models/user_test.rb
  test "should follow and unfollow a user" do
    michael = users(:michael)
    archer = users(:archer)
    assert_not michael.following?(archer)
    michael.follow(archer)
    assert michael.following?(archer)
    assert archer.follower.include?(michael)
    michael.unfollow(archer)
    assert_not michael.following?(archer)
  end
```

####動作確認
テストがgreenになることを確認。

```irb
yokoyan:~/workspace/sample_app (following-users) $ rails test
Running via Spring preloader in process 5854
Started with run options --seed 4043

DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only=======================                               ] 77% Time: 00:00:03,  ETA: 00:00:01
the following keyword arguments in future Rails versions:
params, headers, env, xhr, as

Examples:

get '/profile',
  params: { id: 1 },
  headers: { 'X-Extra-Header' => '123' },
  env: { 'action_dispatch.custom' => 'custom' },
  xhr: true,
  as: :json
 (called from block (2 levels) in <class:MicropostsInterfaceTest> at /home/ubuntu/workspace/sample_app/test/integration/microposts_interface_test.rb:27)
  63/63: [=====================================================================================================================================] 100% Time: 00:00:05, Time: 00:00:05

Finished in 5.26879s
63 tests, 269 assertions, 0 failures, 0 errors, 0 skips
```

###演習1
*コンソールを開き、何人かのユーザーが最初のユーザーをフォローしている状況を作ってみてください。最初のユーザーをuserとすると、user.followers.map(&:id)の値はどのようになっているでしょうか?*

最初のユーザから、4番目までのユーザを作成する。

```irb
yokoyan:~/workspace/sample_app (following-users) $ rails console --sandbox
Running via Spring preloader in process 6034
Loading development environment in sandbox (Rails 5.0.0.1)
Any modifications you make will be rolled back on exit
>> 
?> user = User.first
  User Load (0.6ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-07-26 21:31:59", updated_at: "2017-07-26 21:31:59", password_digest: "$2a$10$hr3puKUHMOdKoV.IkakM0uxzu3mOW./qM63oJ6Xq3q9...", remember_digest: nil, admin: true, activation_digest: "$2a$10$g6M8JTC1B48HIxzpi6iy8.qBKbQsxyaRos1ldkd2q9n...", activated: true, activated_at: "2017-07-26 21:31:59", reset_digest: nil, reset_sent_at: nil>
>> 
?> user2 = User.second
  User Load (0.3ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 1]]
=> #<User id: 2, name: "Chester Greenfelder III", email: "example-1@railstutorial.org", created_at: "2017-07-26 21:32:00", updated_at: "2017-07-26 21:32:00", password_digest: "$2a$10$OEftiG18yO2djfYF/Qd2yODa4aYbgFbLpgWRhX9zw/....", remember_digest: nil, admin: false, activation_digest: "$2a$10$tnRwE2WFuUJiQ4BlKEXbne1h2Ejr.8LrUPA7FY.WQMw...", activated: true, activated_at: "2017-07-26 21:32:00", reset_digest: nil, reset_sent_at: nil>
>> 
u?> user3 = User.third
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 2]]
=> #<User id: 3, name: "Chad Runolfsdottir", email: "example-2@railstutorial.org", created_at: "2017-07-26 21:32:00", updated_at: "2017-07-26 21:32:00", password_digest: "$2a$10$JobCCI0QOmLfs6UN4SykdeCm4qGJv29oIWahAIxIAuR...", remember_digest: nil, admin: false, activation_digest: "$2a$10$ln97hpFaoM4p8escgCyvVO30Sh.Z7h2ZQoGPCDMfcao...", activated: true, activated_at: "2017-07-26 21:32:00", reset_digest: nil, reset_sent_at: nil>
>> 
?> user4 = User.fourth
  User Load (0.2ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? OFFSET ?  [["LIMIT", 1], ["OFFSET", 3]]
=> #<User id: 4, name: "Alexandro Lemke", email: "example-3@railstutorial.org", created_at: "2017-07-26 21:32:00", updated_at: "2017-07-26 21:32:00", password_digest: "$2a$10$9bcHizLobKZITlg1egPVy.z0R1AUN800245UXxH71Ct...", remember_digest: nil, admin: false, activation_digest: "$2a$10$lQQRPpzraXZ/uQ/x8FFhyunDpLaLlpMX6gB5O2b4fML...", activated: true, activated_at: "2017-07-26 21:32:00", reset_digest: nil, reset_sent_at: nil>
```

3人のユーザが最初のユーザーをフォローする。

```irb
>> 
?> user2.follow(user)
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.9ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 2], ["followed_id", 1], ["created_at", 2017-08-26 04:05:32 UTC], ["updated_at", 2017-08-26 04:05:32 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 1, follower_id: 2, followed_id: 1, created_at: "2017-08-26 04:05:32", updated_at: "2017-08-26 04:05:32">
>> 
?> user3.follow(user)
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.5ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 3], ["followed_id", 1], ["created_at", 2017-08-26 04:05:41 UTC], ["updated_at", 2017-08-26 04:05:41 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 2, follower_id: 3, followed_id: 1, created_at: "2017-08-26 04:05:41", updated_at: "2017-08-26 04:05:41">
>> 
?> user4.follow(user)
   (0.1ms)  SAVEPOINT active_record_1
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 4], ["LIMIT", 1]]
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  SQL (0.3ms)  INSERT INTO "relationships" ("follower_id", "followed_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["follower_id", 4], ["followed_id", 1], ["created_at", 2017-08-26 04:05:53 UTC], ["updated_at", 2017-08-26 04:05:53 UTC]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> #<Relationship id: 3, follower_id: 4, followed_id: 1, created_at: "2017-08-26 04:05:53", updated_at: "2017-08-26 04:05:53">
```

最初のユーザーのフォロー数を確認する。
3人のユーザからフォローされていることを確認。

```irb
?> user.followers.map(&:id)
  User Load (0.4ms)  SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> [2, 3, 4]
```

###演習2
*上の演習が終わったら、user.followers.countの実行結果が、先ほどフォローさせたユーザー数と一致していることを確認してみましょう。

```irb
?> user.followers.count
   (0.3ms)  SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ?  [["followed_id", 1]]
=> 3
```

###演習3
*user.followers.countを実行した結果、出力されるSQL文はどのような内容になっているでしょうか? また、user.followers.to_a.countの実行結果と違っている箇所はありますか? ヒント: もしuserに100万人のフォロワーがいた場合、どのような違いがあるでしょうか? 考えてみてください。*

`user.followers.to_a.count`でも、同じく3が返ってくる。
100万人のフォロワーがいた場合、100万人分の配列を生成してその数を返す。
配列を生成する分、実行コストがかかると思われる。

一方、`user.followers.count`は、Railsは高速化のためにDB内で合計を計算する。

```irb
?> user.followers.to_a.count
=> 3
```

#おわりに
ついに最後の章に入りました！
これまでのモデルに比べると、多対多の関係となっているため複雑です。
モデル間の構造を意識しながら、これからもプログラムを書いていきます。