railsチュートリアル　第十四章　

##はじめに
この記事では、railsチュートリアル第１４章の復習として行程をようやくしたものとなっています。

##ユーザーをフォローする

第１４章では**他のユーザーをフォロー (およびフォロー解除) できるソーシャルな仕組み**の追加と、**フォローしているユーザーの投稿をステータスフィードに表示する機能**を追加していく。

###Relationshipモデル

ユーザーをフォローする機能を実装する第一歩は、**データモデルを構成**することとなる。

「1人のユーザーが複数のユーザーをhas_manyとしてフォローし、1人のユーザーに複数のフォロワーがいることをhas_manyで表す」

といった方法でも実装できそうだが、これでは問題が出てきてしまう。

上記のようにテーブル構造すると、非常に無駄が多く更新も大きな手間となってしまう事になる。

この問題の根本は、必要な抽象化を行なっていないことであり、正しいモデルを見つけ出す方法の1つは、Webアプリケーションにおける ```following``` の動作をどのように実装するかを観察することである。

ここを観察すると、フォローまたはアンフォローで作成または削除されるのは、つまるところ2人のユーザーの**「関係 (リレーションシップ)」**であることがわかる。

リレーションシップを経由することによって**1人のユーザーは1対多の関係**を持つことができ、さらに**ユーザーは多くのfollowing (またはfollowers) と関係**を持つことができるということになる。

また、Facebookのような友好関係 (Friendships) では本質的に左右対称のデータモデルが成り立つが、Twitterのようなフォロー関係では左右非対称の性質がある。

このような左右非対称な関係性を見分けるために、それぞれを**能動的関係 (Active Relationship)**と**受動的関係 (Passive Relationship)**と呼ぶことにする。


まずは、フォローしているユーザーを生成するために、**能動的関係**に焦点を当てていく。

フォローしているユーザーはfollowed_idがあれば識別することができるので、```active_relationshipsテーブル```を作り、そこを経由することによって効率的なモデル構造を作る。

このデータモデルを実装するために、まずは次のようなマイグレーションを生成する。

```
$ rails generate model Relationship follower_id:integer followed_id:integer
```

このリレーションシップは今後 ```follower_id``` と ```followed_id``` で頻繁に検索することになるから、それぞれのカラムに**インデックス**を追加しておく。

```db/migrate/[timestamp]_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
```
↑のマイグレーションファイルの、

```add_index :relationships, [:follower_id, :followed_id], unique: true```

という複合キーインデックスは、follower_idとfollowed_idの組み合わせが必ず**ユニーク**であることを保証する仕組みであり、これにより、あるユーザーが同じユーザーを2回以上フォローすることを防ぐ。

```relationshipsテーブル``` を作成するために、いつものようにデータベースのマイグレーションを行う。

```
$ rails db:migrate
```

###User/Relationshipの関連付け

フォローしているユーザーとフォロワーを実装する前に、**UserとRelationshipの関連付け**を行う。

1人のユーザーには**has_many (1対多)** のリレーションシップがあり、このリレーションシップは2人のユーザーの間の関係となるから、フォローしているユーザーとフォロワーの両方に属す。 **(belongs_to)**


今回のケースではフォローしているユーザーを ```follower_id```    という外部キーを使って特定しなくてはならない。

また、followerというクラス名は存在しないので、ここでもRailsに正しいクラス名を伝える必要がある。

能動的関係に対して1対多 (has_many) の関連付けを実装する

```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
  .
  .
  .
end
```
上記では、ユーザーを削除したら、ユーザーのリレーションシップも同時に削除される必要あるため、関連付けに```dependent: :destroy```も追加している。

followerの関連付けについては現段階では使わないが、```follower``` と ```followed``` を対称的に実装しておくことで、構造に対する理解は容易になる。

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

上記で定義した関連付けにより下のようなメソッドが使用できるようになった。

| メソッド | 用途 |
|:--|:--|
| active_relationship.follower | フォロワーを返す |
| active_relationship.followed | フォローしているユーザーを返す |
| user.active_relationships.create(followed_id: other_user.id) | userと紐付けて能動的関係を作成/登録する |
| user.active_relationships.create!(followed_id: other_user.id) | userを紐付けて能動的関係を作成/登録する (失敗時にエラーを出力) |
| user.active_relationships.build(followed_id: other_user.id) | userと紐付けた新しいRelationshipオブジェクトを返す |

###Relationshipのバリデーション

ここで存在性のバリデーションを与えておく。

```app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
  validates :follower_id, presence: true
  validates :followed_id, presence: true
end
```

###フォローしているユーザー
followingとfollowersに関して今回は```has_many through```を使う。

デフォルトのhas_many throughという関連付けでは、Railsはモデル名 (単数形) に対応する外部キーを探す。


```
has_many :followeds, through: :active_relationships
```

上のコードの場合、Railsは「followeds」というシンボル名を見て、これを「followed」という単数形に変え、 relationshipsテーブルのfollowed_idを使って対象のユーザーを取得してくる。

ただ、user.followedsという名前は英語として不適切となる。

代わりに、```user.following```という名前を使うことにする。
そのためには、Railsのデフォルトを上書きする必要があり、ここでは```:sourceパラメーター```を使って**「following配列の元はfollowed idの集合である」**ということを明示的にRailsに伝える必要がある。
Userモデルにfollowingの関連付けを追加する↓

```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 :following, through: :active_relationships, source: :followed
  .
  .
  .
end
 ```

次に、followingで取得した集合をより簡単に取り扱うために、```follow``` や ```unfollow``` といった便利メソッドを追加する。
 "following" 関連のメソッド ↓

```app/models/user.rb
class User < ApplicationRecord
  .
  .
  .
  def feed
    .
    .
    .
  end

  # ユーザーをフォローする
  def follow(other_user)
    following << other_user
  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

  private
  .
  .
  .
end
```

###フォロワー

ここでuser.followersメソッドを追加していく。

これは上のuser.followingメソッドと対になり、フォロワーの配列を展開するために必要な情報は、```relationshipsテーブル```に既にある。

よって、**follower_idとfollowed_idを入れ替える**だけで、フォロワーについてもフォローする場合と全く同じ方法が活用できる。
受動的関係を使ってuser.followersを実装する↓

```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
  .
  .
  .
end
```
```:followers属性``` の場合、Railsが「followers」を単数形にして自動的に外部キーfollower_idを探してくれるから ```:sourceキー``` を省略してもイイが ```has_many :following``` との類似性を強調させるため残しておく。

##[Follow] のWebインターフェイス
この節では、フォロー/フォロー解除の基本的なインターフェイスを実装、また、フォローしているユーザーと、フォロワーにそれぞれ表示用のページを作成する。

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

前の章のときと同じように、サンプルデータを自動作成する ```rails db:seed``` を使って、データベースにサンプルデータを登録しておく。

先にサンプルデータを自動作成できるようにしておけば、Webページの見た目のデザインから先にとりかかることができ、バックエンド機能の実装を後に回すことができるというメリットがある。

サンプルデータにfollowing/followerの関係性を追加する↓

```db/seeds.rb
#省略

# リレーションシップ
users = User.all
user  = users.first
following = users[2..50]
followers = users[3..40]
following.each { |followed| user.follow(followed) }
followers.each { |follower| follower.follow(user) }
```
ここでは、**最初のユーザーにユーザー3からユーザー51までをフォローさせ、それから逆にユーザー4からユーザー41に最初のユーザーをフォロー**させる。

データベース上のサンプルデータを作り直すために、いつものコマンドを実行する。

```
$ rails db:migrate:reset
$ rails db:seed
```

###統計と [Follow] フォーム

これでサンプルユーザーに、フォローしているユーザーとフォロワーができた。

**プロフィールページ**と**Homeページ**を更新して、これを反映する。

次にUsersコントローラにfollowingアクションとfollowersアクションを追加する↓

```config/routes.rb
Rails.application.routes.draw do
  root   'static_pages#home'
  get    '/help',    to: 'static_pages#help'
  get    '/about',   to: 'static_pages#about'
  get    '/contact', to: 'static_pages#contact'
  get    '/signup',  to: 'users#new'
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'
  #追加
  resources :users do
    member do
      get :following, :followers
    end
  end

  resources :account_activations, only: [:edit]
  resources :password_resets,     only: [:new, :create, :edit, :update]
  resources :microposts,          only: [:create, :destroy]
end
```

↑によって生成されるルーティングテーブルを下に示す

| HTTPリクエスト | URL | アクション | 名前付きルート |
|:--|:--|:--|:--|
| GET | /users/1/following | following | following_user_path(1) |
| GET | /users/1/followers | followers | followers_user_path(1) |

ルーティングを定義したので、統計情報のパーシャルを実装する。

```app/views/shared/_stats.html.erb
<% @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>
```

```<% @user ||= current_user %>```
このコードは、@userがnilでない場合 (つまりプロフィールページの場合) は何もせず、nilの場合 (つまりHomeページの場合) には@userにcurrent_userを代入するコードとなる。

また、
```<strong id="following" class="stat">
...
</strong>
```
こうしておくと、**Ajax**を実装するときに便利となる。

これを**Homeページ**に表示する。

```app/views/static_pages/home.html.erb
<% if logged_in? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      #追加
      <section class="stats">
        <%= render 'shared/stats' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
    <div class="col-md-8">
      <h3>Micropost Feed</h3>
      <%= render 'shared/feed' %>
    </div>
  </div>
<% else %>
  .
  .
  .
<% end %>
```

また必要に応じてSCSSにスタイルを加える。

次の行程として**[Follow] / [Unfollow] ボタン用のパーシャル**も作成しておく。

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

このコードは、**follow**と**unfollow**のパーシャルに作業を振っているだけになるからRelationshipsリソース用の新しいルーティングを追加し、フォロー/フォロー解除用のパーシャルを個別に用意する必要がある。

Relationshipリソース用のルーティングを追加する↓


```config/routes.rb
#省略

resources :relationships,       only: [:create, :destroy]
end
```
ユーザーをフォローするフォーム↓

```app/views/users/_follow.html.erb
<%= form_for(current_user.active_relationships.build) do |f| %>
  <div><%= hidden_field_tag :followed_id, @user.id %></div>
  <%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
```
ユーザーをフォロー解除するフォーム↓

```app/views/users/_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
             html: { method: :delete }) do |f| %>
  <%= f.submit "Unfollow", class: "btn" %>
<% end %>
```


これでパーシャルとしてフォロー用フォームをプロフィールページに表示できるようになった。

プロフィールページにフォロー用フォームとフォロワーの統計情報を追加する↓

```app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user %>
        <%= @user.name %>
      </h1>
    </section>
    #追加
    <section class="stats">
      <%= render 'shared/stats' %>
    </section>

  </aside>
  <div class="col-md-8">
    #追加
    <%= render 'follow_form' if logged_in? %>
    <% if @user.microposts.any? %>
      <h3>Microposts (<%= @user.microposts.count %>)</h3>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>
</div>
```

**この[Follow] / [Unfollow] ボタンの実装には標準的な方法とAjaxを使う方法の２つがある。**

その前に、フォローしているユーザーとフォロワーを表示するページをそれぞれ作成してHTMLインターフェイスを完成させる。

###[Following] と [Followers] ページ

フォローしているユーザーを表示するページと、フォロワーを表示するページは、いずれも**プロフィールページとユーザー一覧ページを合わせたもの**のようになる。

ここでの最初の作業は、フォローしているユーザーのリンクとフォロワーのリンクを動くようにすることとなる。

 Twitterに倣って、どちらのページでもユーザーのログインを要求するようにする。

```app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy,
                                        :following, :followers]
  .
  .
  .
  def following
    @title = "Following"
    @user  = User.find(params[:id])
    @users = @user.following.paginate(page: params[:page])
    render 'show_follow'
  end

  def followers
    @title = "Followers"
    @user  = User.find(params[:id])
    @users = @user.followers.paginate(page: params[:page])
    render 'show_follow'
  end

  private
  .
  .
  .
end
```

Railsは慣習に従って、アクションに対応するビューを暗黙的に呼び出す。
上記でも、renderを明示的に呼び出し、show_followという同じビューを出力している。したがって、作成が必要なビューはこれ1つですむ。

フォローしているユーザーとフォロワーの両方を表示するshow_followビュー↓

```app/views/users/show_follow.html.erb
<% provide(:title, @title) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <%= gravatar_for @user %>
      <h1><%= @user.name %></h1>
      <span><%= link_to "view my profile", @user %></span>
      <span><b>Microposts:</b> <%= @user.microposts.count %></span>
    </section>
    <section class="stats">
      <%= render 'shared/stats' %>
      <% if @users.any? %>
        <div class="user_avatars">
          <% @users.each do |user| %>
            <%= link_to gravatar_for(user, size: 30), user %>
          <% end %>
        </div>
      <% end %>
    </section>
  </aside>
  <div class="col-md-8">
    <h3><%= @title %></h3>
    <% if @users.any? %>
      <ul class="users follow">
        <%= render @users %>
      </ul>
      <%= will_paginate %>
    <% end %>
  </div>
</div>
```


###[Follow] ボタン (基本編)

フォローとフォロー解除はそれぞれリレーションシップの作成と削除に対応しているため、まずは```Relationshipsコントローラ```が必要となる。

```
$ rails generate controller Relationships
```
次に、```logged_in_userフィルター```を**Relationshipsコントローラのアクションに対して追加**する。

```app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
  before_action :logged_in_user

  def create
  end

  def destroy
  end
end

```
[Follow] / [Unfollow] ボタンを動作させるためには、フォームから送信されたパラメータを使って、```followed_id``` に対応するユーザーを見つけてくる必要がある。

その後、見つけてきたユーザーに対して適切に ```follow/unfollowメソッド``` を使う。

Relationshipsコントローラ↓

```app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
  before_action :logged_in_user

  def create
    user = User.find(params[:followed_id])
    current_user.follow(user)
    redirect_to user
  end

  def destroy
    user = Relationship.find(params[:id]).followed
    current_user.unfollow(user)
    redirect_to user
  end
end
```

これにより、フォロー/フォロー解除の機能が完成した。

###[Follow] ボタン (Ajax編)
上記ではRelationshipsコントローラの ```createアクション``` と ```destroyアクション``` を単に元の**プロフィールにリダイレクト**していた。

ここで、```Ajax```を使えば、Webページからサーバーに**「非同期」**で、ページを移動することなくリクエストを送信することができる。

**WebフォームにAjaxを採用する**のは今や当たり前になりつつあるので、RailsでもAjaxを簡単に実装できるようになっている。

**form_for**

というコードを

**form_for ..., remote: true**

と置き換えるだけで、Railsは自動的にAjaxを使うようになる。
 Ajaxを使ったフォローフォーム↓


```app/views/users/_follow.html.erb
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
  <div><%= hidden_field_tag :followed_id, @user.id %></div>
  <%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
 ```
Ajaxを使ったフォロー解除フォーム↓

```app/views/users/_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
             html: { method: :delete },
             remote: true) do |f| %>
  <%= f.submit "Unfollow", class: "btn" %>
<% end %>
```

フォームの更新が終わったので、今度はこれに対応する```Relationshipsコントローラ```を改造して、**Ajaxリクエストに応答できる**ようにする。

こういったリクエストの種類によって応答を場合分けするときは、```respond_toメソッド```というメソッドを使うようにする。

```
respond_to do |format|
  format.html { redirect_to user }
  format.js
end
```

上の (ブロック内の) コードのうち、いずれかの1行が実行される。

**RelationshipsコントローラでAjaxに対応させるために、respond_toメソッドをcreateアクションとdestroyアクションに追加**する。

```app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
  before_action :logged_in_user

  def create
    @user = User.find(params[:followed_id])
    current_user.follow(@user)
    #追加修正
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end

  def destroy
    @user = Relationship.find(params[:id]).followed
    current_user.unfollow(@user)
    #追加修正
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end
end
```

ビューで変数を使うため、userが@userに変わっている

今度はブラウザ側で**JavaScriptが無効になっていた場合 (Ajaxリクエストが送れない場合) でもうまく動く**ようにする。

```config/application.rb
require File.expand_path('../boot', __FILE__)
.
.
.
module SampleApp
  class Application < Rails::Application
    .
    .
    .
    # 認証トークンをremoteフォームに埋め込む
    config.action_view.embed_authenticity_token_in_remote_forms = true
  end
end
```

###.js.erbファイル
JavaScriptが有効になっていても、まだ十分に対応できていない部分がある。

というのも、Ajaxリクエストを受信した場合は、**Railsが自動的にアクションと同じ名前を持つJavaScript用の埋め込みRuby (.js.erb) ファイル (create.js.erbやdestroy.js.erbなど) を呼び出指定しまうから**である。

なのでファイルを新たに作成する必要がある。

JS-ERbファイルの内部では、DOM (Document Object Model) を使ってページを操作するため、RailsがjQuery JavaScriptヘルパーを自動的に提供している。

 JavaScriptと埋め込みRubyを使ってフォローの関係性を作成する↓

```app/views/relationships/create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= @user.followers.count %>');
```

Ruby JavaScript (RJS) を使ってフォローの関係性を削除する↓

```app/views/relationships/destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= @user.followers.count %>');
```

これらのコードにより、プロフィールページを更新させずにフォローとフォロー解除ができるようになった。

##ステータスフィード
現在のユーザーにフォローされているユーザーのマイクロポストの配列を作成し、現在のユーザー自身のマイクロポストと合わせて表示する。


ステータスフィードを実装するには**現在のユーザーによってフォローされているユーザーに対応するユーザーidを持つマイクロポストを取り出し、同時に現在のユーザー自身のマイクロポストも一緒に取り出すようにする**必要がある。

フィードに必要な３つの条件を下に示す。

>・フォローしているユーザーのマイクロポストがフィードに含まれていること。
・自分自身のマイクロポストもフィードに含まれていること。
・フォローしていないユーザーのマイクロポストがフィードに含まれていないこと

最初に、このフィードで必要なクエリについて考えてみる。
ここで必要なのは、```micropostsテーブル``` から、**あるユーザー (つまり自分自身) がフォローしているユーザーに対応するidを持つマイクロポストをすべて選択 (select)** することである。

このクエリを模式的に書くと次のようになる。

```SELECT * FROM microposts
WHERE user_id IN (<list of ids>) OR user_id = <user id>```

↑を参考に、今回必要になる選択は、上よりも少し複雑で、例えば次のような形になる。

```Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)```

この```following_idsメソッド```は、**has_many :followingの関連付けをしたときにActive Recordが自動生成したもの**である。

これにより、user.followingコレクションに対応するidを得るためには、関連付けの名前の末尾に**_ids**を付け足すだけで済む。

```app/models/user.rb
class User < ApplicationRecord
  .
  .
  .
  # パスワード再設定の期限が切れている場合はtrueを返す
  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  end

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

  # ユーザーをフォローする
  def follow(other_user)
    following << other_user
  end
  .
  .
  .
end
```

###サブセレクト
問題点として上記のフィードの実装は、投稿されたマイクロポストの数が膨大になったときにうまくスケールしない、つまり、フォローしているユーザーが5,000人程度になるとWebサービス全体が遅くなる可能性がある。

上に示したコードの問題点は、following_idsでフォローしているすべてのユーザーをデータベースに問い合わせし、さらに、フォローしているユーザーの完全な配列を作るために再度データベースに問い合わせしている点である。

このような問題は、**SQLのサブセレクト(subselect)**を使うと解決できる。

まずはコードを若干修正し、フィードをリファクタリングすることから始める。

 whereメソッド内の変数に、キーと値のペアを使う↓

```app/models/user.rb
class User < ApplicationRecord
  .
  .
  .
  # ユーザーのステータスフィードを返す
  def feed
    Micropost.where("user_id IN (:following_ids) OR user_id = :user_id",
     following_ids: following_ids, user_id: id)
  end
  .
  .
  .
end
```

前者の疑問符を使った文法も便利だが、同じ変数を複数の場所に挿入したい場合は、後者の置き換え後の文法を使う方がより便利になる。

上記では**following_idsをSQLのサブセレクト**として使う。
つまり、「ユーザー1がフォローしているユーザーすべてを選択する」というSQLを既存のSQLに内包させる形になり、結果としてSQLは次のようになる。

```SELECT * FROM microposts
WHERE user_id IN (SELECT followed_id FROM relationships
                  WHERE  follower_id = 1)
      OR user_id = 1
```

これでもっと効率的なフィードを実装する準備がきた。
フィードの最終的な実装↓

```app/models/user.rb
class User < ApplicationRecord
  .
  .
  .
  # ユーザーのステータスフィードを返す
  def feed
    following_ids = "SELECT followed_id FROM relationships
                     WHERE follower_id = :user_id"
    Micropost.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
  end
  .
  .
  .
end
```
(ここに記述されているコードは生のSQLを表す文字列であり、following_idsという文字列はエスケープされているのではなく、見やすさのために式展開している)

これでステータスフィードの実装は完了。

##さいごに
これでrailsチュートリアルを全て完走した。
ここで出てくる知識はサービスを作る上で基本になるところだろうからしっかり復習して自分の知識にしようと思う。

ここにプラスアルファで返信機能などもつけることを演習として推奨されているのでまた挑戦してみようと思う。