LoginSignup
35

More than 5 years have passed since last update.

[Rails]いいね機能実装

Last updated at Posted at 2017-09-14

目標

0076efc1fe0ec660007d29f6eb82f0bd.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

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ファイルはこれだけです。
以上で完成となります。

参考サイト

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35