ユーザー(user)が出品した商品(item)にいいねできる機能を実装してます。
Likeモデル、テーブル作成
rails g model Like
class Like < ApplicationRecord
end
class CreateLikes < ActiveRecord::Migration[5.2]
def change
create_table :likes do |t|
t.integer :user_id
t.integer :item_id
t.timestamps
end
end
end
rails db:migrate
マイグレーションファイル実行
モデル
通常はuserとitemは1対多の関係ですが、いいね機能実装時に関してはlikeテーブルが加わるので、多対多の関係になります。
has_many :likes, dependent: :destroy
has_many :like_items, through: :likes, source: :item
has_many :likes, dependent: :destroy
has_many :liking_users, through: :likes, source: :user
dependent: :destroy
はいいねを外した時に、中間likesテーブルにある該当userとitemのレコードを一緒に削除してくれます。
:like_items
はuserがどのitemをいいねしているのかを取得
:liking_users
はitemがどのuserによっていいねされているのか取得
through: :likes
は多対多の関係で中間likeテーブルを経由するための関連付けで記述
source:
オプションは関連付け元の名前を指定するため記述
class Like < ApplicationRecord
belongs_to :item, counter_cache: :likes_count
belongs_to :user
end
counter_cahce: :likes_count
はリレーションされているlikeの数の値をリレーション先のlikes_countというカラムの値に入れるという意味です。なのでlikes_countカラムをitemsテーブルに追加しましょう。
itemsテーブルにlikes_countカラム追加
rails g migration AddLikes_countToItems
class AddLikesCountToItems < ActiveRecord::Migration[5.2]
def change
add_column :items, :likes_count, :integer
end
end
rails db:migrate
マイグレーションファイル実行
ルーティング設定
resources :items
member do
post '/like/:item_id' => 'likes#like', as: 'like'
delete '/like/:item_id' => 'likes#unlike', as: 'unlike'
end
いいねをつける時→like 外す時→unlike
as:でルーティングに名前を付けれる。この二つはlike_path,unlike_pathとして使えるようになります。
コントローラー
rails g contoller likes
class LikesController < ApplicationController
before_action :set_variables
def like
like = current_user.likes.new(item_id: @item.id)
like.save
end
def unlike
like = current_user.likes.find_by(item_id: @item.id)
like.destroy
end
private
def set_variables
@item = Item.find(params[:item_id])
@id_name = "#like-link-#{@item.id}"
end
end
@id_name
は非同期で使用します。
ビュー
.option
= render partial: 'likes/like', locals: { item: @item }
render
を使用し、部分テンプレートへ誘導
likesディレクトリに部分テンプレート_like.html.haml
ファイルを作成
.option__like{:id => "like-link-#{@item.id}"}
- if current_user.likes.find_by(item_id: item.id)
= link_to unlike_item_path(@item.id, @item.id), method: :delete, remote: true, class: "option__like-on" do
.fas.fa-star
.option__like-on__text いいね!
.option__like-on__count
=item.likes.count
- else
= link_to like_item_path(@item.id, @item.id), method: :post, remote: true, class: "option__like-off" do
.fas.fa-star
.option__like-off__text いいね!
.option__like-off__count
=item.likes.count
いいねボタンのビューを記述します。
{:id => "like-link-#{@item.id}"}
をつけることで@itemのボタンであることを指定します。
remote: true
をつけることでリンクを押した時、ajaxを発火させます。
=item.likes.count
でいいねされた数を表示します。
##いいねボタンの非同期化
like.js.haml
とunlike.js.haml
ファイル作成
$("#{@id_name}").html('#{escape_javascript(render("likes/like", item: @item ))}');
$("#{@id_name}").html('#{escape_javascript(render("likes/like", item: @item ))}');
コントローラーで定義した@id_name
を指定し、escape_javascript
で先ほど作成した_likeファイルを埋め込んでます。
Sass
.option {
display: flex;
justify-content: space-between;
&__like {
&-on {
text-decoration: none;
padding: 11px 10px;
border-radius: 40px;
color: #3CCACE;
border: 1px solid #ffb340;
display: flex;
line-height: 16px;
.fas.fa-star {
padding-right: 5px;
}
&__text {
padding-right: 5px;
}
}
&-off {
text-decoration: none;
padding: 11px 10px;
border-radius: 40px;
color: #333;
border: 1px solid #f5f5f5;
display: flex;
line-height: 16px;
background: #f5f5f5;
.fas.fa-star {
padding-right: 5px;
}
&__text {
padding-right: 5px;
}
}
}
}
sassの説明は省略します。
完成イメージ
ユーザーがいいねした商品一覧を表示させたい方はこちらをご覧ください
間違えている部分があったらぜひコメントよろしくお願いします!!