[Rails]いいね機能実装

# 目標
![0076efc1fe0ec660007d29f6eb82f0bd.gif](https://qiita-image-store.s3.amazonaws.com/0/163291/120fe2a6-e7d6-3401-579e-96b6ef65d3c5.gif)


# 開発環境
・Ruby 2.3.1
・Rails 5.1.3

# 使用したモデル
userモデル(誰がいいねするか)
closetモデル(どの服にいいねするか)
likeモデル（いいね自身）

# likesテーブル作成
userモデルやclosetモデル、closetsコントローラーは作成済みで進めていきます。
まずはターミナルでlikeモデルを作成します。その後migrationファイルを以下のように編集しましょう。

```20170827133035_create_likes.rb
class CreateLikes < ActiveRecord::Migration[5.1]
  def change
    create_table :likes do |t|
      t.references :closet, foreign_key: true
      t.references :user, foreign_key: true
      t.timestamps
    end
  end
end
```

# アソシエーションを定義する

```models/like.rb
class Like < ApplicationRecord
  belongs_to :closet
  belongs_to :user
end
```

```models/closet.rb
class Closet < ApplicationRecord
  has_many :likes, dependent: :destroy

  def like_user(id)
    likes.find_by(user_id: id)
  end
end
```
closetが削除されたらそれに紐づくlikeも削除したいのでオプションでdependent: :destroyを記述します。

```models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable

  #いいね機能のアソシエーション
  has_many :likes, dependent: :destroy
end
```
こちらも先ほど同様にオプションでdependent: :destroyを記述します。

# likesコントローラー作成

```likes_controller.rb
class LikesController < ApplicationController

  before_action :set_closet, only: [:create, :destroy]

  def create
    @like = current_user.likes.create(closet_id: params[:closet_id])
    @closets = Closet.all
  end

  def destroy
    like = current_user.likes.find_by(closet_id: params[:closet_id])
    like.destroy
    @closets = Closet.all
  end

  private

  def set_closet
    @closet = Closet.find(params[:closet_id])
  end
end
```

# closetsコントローラーのアクション定義

```closets.controller.rb
class ClosetsController < ApplicationController

  def index
    @closets = Closet.all
  end
end
```

# ルーティング追加

```route.rb
Rails.application.routes.draw do
  resources :closets  do
    resources :likes, only: [:create, :destroy]
  end
end
```

# view作成
今回はslimでviewを記述しています。

```closets/index.html.slim
#js-grid-juicy-projects
  /@closetsをrender先でそれぞれを取り出してclosetとして渡す
  = render @closets
```

```closets/_closet.html.slim
/画像用なので記述しなくてよい
.cbp-caption-defaultWrap
  = image_tag closet.thumbnails.first.image, class: "item-thumbnail-capture item-thumbnail-size"
/ここから必要
.like-link
  = render partial: 'likes/like_links', locals:{ closet: closet }
```
※画像とかじゃなく他の何かにいいねする場合は.like-linkのcssになにかしらの記述いると思います。
いいねボタンを部分テンプレートで渡すのでlikesフォルダをviewsの中に作ります

```views/likes/_like_links.html.slim
- if closet.like_user(current_user.id)
  = link_to closet_like_path(closet, closet.like_user(current_user)), method: :delete, class: 'heart-icon', remote: true do
    .fa.fa-heart.fa-2x.heart-red
- else
  = link_to closet_likes_path(closet), method: :post, class: 'empty-heart', remote: true do
    .fa.fa-heart-o.fa-2x.heart-color
```
ハートマークはgemのfont-awesome-railsを使用して表示させています。
いいねしてるかどうかで条件分岐させ,closet.like_userのlike_userはclosetモデルに記述したメソッドを使ってます。
= link_to closet_like_path(closet, closet.like_user(current_user))の引数なのですが、
第一引数のclosetはclosetsコントローラーからとってこれたのですが、第二引数がコントローラーから持ってくる方法がわからず、モデルに記述したメソッドを使用しました。他にいい方法があれば教えて欲しいです。
ちなみにrake routeした結果がこちらです。
![スクリーンショット 2017-09-14 16.47.01.png](https://qiita-image-store.s3.amazonaws.com/0/163291/90eaea71-10da-b275-a9ac-610b04f41e85.png)

#jsファイル作成

```likes/create.js.erb
$("#js-grid-juicy-projects").html("<%= j(render @closets) %>");
```

```likes/destroy.js.erb
$("#js-grid-juicy-projects").html("<%= j(render @closets) %>");
```

jsファイルはこれだけです。
以上で完成となります。

# 参考サイト
http://qiita.com/YuitoSato/items/94913d6a349a530b2ea2