投稿に対していいね機能を実装する

#概要
今回、twitterのような投稿アプリに対して
いいねを押したり、取り消したりできる機能と、
いいねをカウントして件数を表示できる機能と、
いいねするリンクをハートにする実装についてまとめておきます。

ちなみに、投稿にいいねをする機能に関しては、progateにカリキュラムがありますが、自分はそのまま実装しても思うような機能にならなかったので、qiitaをはじめとするサイトをたくさん検索しました。

それも踏まえてまとめようと思います。

#機能の見た目
![like-qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696517/b20fc7a6-9e6b-4511-d025-cff0e95cf8fa.png)


#実装
####likeモデルを用意する

```
rails g model like
```

マイグレーションファイルに
t.references, foreign_key: trueとして、user_idとpost_idのカラムを設定します。

```models/like.rb
class Like < ApplicationRecord
  validates :user_id, presence: true
  validates :post_id, presence: true
end
```

####ルーティングを設定する

```routes.rb
post "likes/:post_id/create" => "likes#create"
post "likes/:post_id/destroy" => "likes#destroy"
```

これによってrails routesをすると次の画像のようになります。
これは、ビューファイルにリンクを指定するときに必要になるのであとで間違えないようにしましょう。

![like-routes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696517/fb34cc8b-b424-5e50-aef3-994ad4a8d6cc.png)

####コントローラーを作成する

```controllers/likes_controller.rb
class LikesController < ApplicationController
  before_action :authenticate_user!



  def create
    @like = Like.new(user_id: current_user.id, post_id: params[:post_id])
    @like.save
    redirect_to "/posts/#{@like.post_id}"
  end

  def destroy
    @like = Like.find_by(user_id: current_user.id, post_id: params[:post_id])
    @like.destroy
    redirect_to("/posts/#{params[:post_id]}")
  end


end
```

保存や削除をした後にその投稿の詳細ページにリダイレクトされるようになっています。

####ビューファイルを用意しよう

```views/posts/show.html.erb
<div class="like-btn">
    <% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>

      <%=link_to("/likes/#{@post.id}/destroy", {method: :post}) do %>
        <span class="fa fa-heart like-btn-unlike"></span>
      <% end %>

    <% else %>

      <%= link_to("/likes/#{@post.id}/create", {method: :post}) do %>
        <span class="fa fa-heart like-btn"></span>
      <% end %>

    <% end %>
  </div>
```

まずは条件分岐でユーザーがいいねしているかしていないかを分岐し、
ボタンを押したときlikeをcreateするか、destroyするかを指定します。

そして、次に書きますが、link_to ~~~ doとする事で間にHTML文を挟むことができます。(理解が浅ければprogateのrailsカリキュラムを参照)

link_toのURLは間違えないようにしましょう。

先ほどルーティングでのせた画像の通り、/likes/post_id/create(またはdestroy)と記述します。


####いいねをハートアイコンのボタンにする

この部分はprogateを参考にしたのでこれ以外知らないんですけど、
font-awesomeというものを使って、いいねするリンクをボタンにしていきます。

まずはfont-awesomeを使えるようにhead部分にリンクを読み込みます。

```views/layouts/application.html.erb
 ---省略---

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
 </head>
```

ビューファイルはもう適した形式で記述しているので、
最後にいいねしていたらピンク、していなかったらグレーとなるようにcssを記述します。

先ほど記述したviews/posts/show.html.erbを確認すればわかりますが、いいねするボタンと取り消すボタンでlike-btnとlike-btn-unlikeが分かれています。

```assets/stylesheets/likes.scss
.like-btn {
  color: #8899a6;
}


.like-btn-unlike {
  color: #ff2581;
}


.posts-show-item .fa {
  font-size: 16px;
  margin-right: 3px;
}
```

これでハートボタンでいいねしたり取り消したりすることが可能になっているはずです。

最後に、いいねの件数をカウントして表示しましょう。

####件数をカウントして表示する

postsコントローラーのshowメソッドに@like_countを定義してあげて、ビューファイルで表示するような手順になります。

```controllers/posts_controller.rb
def show
    @post = Post.find(params[:id])
    @comment = Comment.new
    @comments = @post.comments.includes(:user)
    @like_count = Like.where(post_id: @post.id).count
 end
```

whereでその投稿についてるいいねをデータベースから検索して、countで数えていくように定義しています。

```views/posts/show.html.erb
<div class="like-btn">

  <h3>いいね件数：<%= @like_count %></h3>

    <% if Like.find_by(user_id: @current_user.id, post_id: @post.id) %>
      <%=link_to("/likes/#{@post.id}/destroy", {method: :post}) do %>
---省略---

```

以上で完成です。