railsでフォロー機能をつける。

メモ

```:環境
rails 5.0.0
ログイン機能は、deviseで作っている。
```
###フォロー機能つける前の状態

　　　　　　   　deviseで、userモデルを作っている。パスワード以下の項目は省略



|id       |      名前  |   　メールアドレス   |
|:-----------------|------------------:|:------------------:|
| １               |           山田  |       yamada@yahoo.co.jp        |
|  ２           |           佐藤 |       satouu@gmail.com            |
|  ３             |             山本 |       yamamoto@yahoo.co.jp          |

　

本の登録するために、bookモデルを作っている。　内容は、本のタイトルと感想です。


| bookモデル      |        |     
|:-----------------|------------------:|:------------------:
| id            |      本のid       |      
|   title        |           本のタイトル |      
| content           |              本の感想　　
| user_id               |                ユーザーid |




ターミナルで以下をします。
＄rails generate model Relationship follower_id:integer following_id:integer

indexを追加、follower_idとfollowing_idをセットで一意にする。

```ruby.20170416132621_create_relationships.rb

class CreateRelationships < ActiveRecord::Migration[5.0]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :following_id

      t.timestamps null: false
    end

    add_index :relationships, :follower_id
    add_index :relationships, :following_id
    add_index :relationships, [:follower_id, :following_id], unique: true
  end
end
```

マイグレーションをする。

```
　$rake db:migrate
```

###フォローできるユーザーを取り出すに記述する。（`user.following_relationships.followings`をできるようにする）

```ruby:app/models/user.rb
has_many :following_relationships, foreign_key: "follower_id", class_name: "Relationship", dependent: :destroy
```

`relationships.following`をできるようにする。

```rb:app/models/relationship.rb
 belongs_to :following, class_name: "User"
 validates :following_id, presence: true
```

１対多の関係になる。

###フォローしているユーザーを取り出す （`user.followings`をできるようにする）

```rb:app/models/user.rb
has_many :following_relationships, foreign_key: "follower_id", class_name: "Relationship", dependent: :destroy

has_many :followings, through: :following_relationships
```


```rb:app/models/relationship.rb
    belongs_to :follower, class_name: "User"
    belongs_to :following, class_name: "User"
    validates :follower_id, presence: true
    validates :following_id, presence: true
```

###user.rbにフォローする関数、フォローしているか調べるための関数、フォローを外す関数を作成する
```rb:app/models/user.rb
 has_many :following_relationships, foreign_key: "follower_id", class_name: "Relationship", dependent: :destroy

 has_many :followings, through: :following_relationships

  def following?(other_user)
    following_relationships.find_by(following_id: other_user.id)
  end

  def follow!(other_user)
    following_relationships.create!(following_id: other_user.id)
  end

  def unfollow!(other_user)
    following_relationships.find_by(following_id: other_user.id).destroy
  end
```

###フォローされているユーザーを取り出す（`user.follwers`をできるようにする）
```rb:app/models/user.rb
 has_many :following_relationships, foreign_key: "follower_id", class_name: "Relationship", dependent: :destroy

 has_many :followings, through: :following_relationships

 has_many :follower_relationships, foreign_key: "following_id", class_name: "Relationship", dependent: :destroy

 has_many :followers, through: :follower_relationships

  def following?(other_user)
    following_relationships.find_by(following_id: other_user.id)
  end

  def follow!(other_user)
    following_relationships.create!(following_id: other_user.id)
  end

  def unfollow!(other_user)
    following_relationships.find_by(following_id: other_user.id).destroy
  end
```

###フォロー機能のルーティング


```rb:config/routes
 resources :users do
    member do
     get :following, :followers
    end
  end
  resources :relationships,       only: [:create, :destroy]
```
###users/showに、追加
フォローするために、各ユーザーに二つの機能をつける。一つ目は、フォローしている人数とフォローされている人数を示す表示。その数字を押すと、フォローしている/フォローされている人の一覧が出てくる。

二つ目は、このユーザーをフォローする/フォロー解除のボタンである。

![s_screenshot 3.png](https://qiita-image-store.s3.amazonaws.com/0/167576/db75fa48-a0bd-bad4-c21b-23745bcd7623.png)

写真の説明
　一人目のユーザーでログインしている。一つ目のユーザーが、users/showの画面で、ユーザー二人目を見てる。

###users/showに追加
deviseでは、user/showは、作られない。だからuser/showをroutesとコントール、viewを付け加える。

デザインは、無視して表示だけ書きます。

```erb:app/view/users/show
　　　<%= render 'follow_form' %>
　　　<%= render 'stats' %>
```
*app/users/showの説明*
renderで他のところから持ってくる。
 
#### 一つ目のフォローしている人数とフォローされている人数を示す表示。
その数字を押すと、フォローしている、フォローされている人の一覧が出てくる画面を作っていく。

```erb:app/views/users/_stats.html.erb
 <% @user ||= current_user %>
<div class="stats">
  <a href="<%= following_user_path(@user) %>">
    <strong id="following" class="stat">
      <%= @user.followings.count %>
    </strong>
    following
  </a>
  <a href="<%= followers_user_path(@user) %>">
    <strong id="followers" class="stat">
      <%= @user.followers.count %>
    </strong>
    followers
  </a>
</div>
```
*app/views/users/_stats.html.erb*の説明
この画面で、フォローしている人数とフォローされている人数を表示する。`<%= following_user_path(@user) %>`と`<%= followers_user_path(@user) %>`のリンクがある。これらの二つに対応するcontrollerとviewを作って行く。

```rb:app/controllers/users_controller.rb
  def following
      @user  = User.find(params[:id])
      @users = @user.followings
      render 'show_follow'
  end

  def followers
    @user  = User.find(params[:id])
    @users = @user.followers
    render 'show_follower'
  end
```
```erb:app/views/users/show_follow.html.erb
<% @user.followings.each do |user| %>
<table>
<tr>
  <td>  <%= user.username %> </td>
  <td><%= link_to '詳細', user_path(user) %></td>
</tr>

</table>
<% end %>
```
*app/views/users/show_follow.html.erbの説明*
　　フォローしている人の名前の一覧の画面

```erb:app/views/users/show_follower.html.erb
 <% @user.followers.each do |user| %>
<table>
<tr>
  <td>  <%= user.username %> </td>
  <td><%= link_to '詳細', user_path(user) %></td>
</tr>

</table>
<% end %>
```
*app/views/users/show_follower.html.erbの説明*
フォローされている人の一覧画面

####補足説明　routesは、これでやっています。
```ruby:config/routes.rb
  resources :users do
    member do
     get :following, :followers
    end
  end
```

これで、フォローしている人数とフォローされている人数をカウント表示と一覧は完成です。

###二つ目の機能を作る。他のユーザーのフォロー、フォローを解除する。

```ruby:config/roures.rb
   resources :relationships, only: [:create, :destroy]
```

```erb: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 %>  
```
```rb:app/helpers/users_helper.rb
  def current_user?(user)
     user == current_user
  end
```
*app/views/users/_follow_form.html.erbの説明*
 　一行目`<% unless current_user?(@user) %>`
このコードで、現在ログインしているユーザーのプロフィールは、フォロー、フォロー解除のボタンが出ないようにする。

三行目からのifの説明。
ユーザーがフォローしている場合は、フォロー解除ボタンを表示。
してない場合は、フォローボタン表示させる。

###フォローボタン、フォロー解除のボタンの機能
 
```erb:app/views/users/_unfollow.html.erb
<%= form_for(current_user.following_relationships.find_by(following_id: @user.id), html: { method: :delete }) do |f| %>
  <%= f.submit "Unfollow", class: "btn btn-large follow-btn" %>
<% end %>
```
```erb:app/views/users/_follow.html.erb
 <%= form_for(current_user.following_relationships.build(following_id: @user.id)) do |f| %>
  <div><%= f.hidden_field :following_id %></div>
  <%= f.submit "Follow", class: "btn btn-large btn-primary follow-btn" %>
<% end %>
```


```rb:app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
  
   def create
    @user = User.find(params[:relationship][:following_id])
    current_user.follow!(@user)
    redirect_to @user
  end

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

これで完成。