はじめに
今回はSNSアプリでデフォルトと言っていいほど備わっている機能(いいね)の実装方法について記載します。
開発環境、前提条件
- AWS Cloud9
- Ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
- Rails 6.1.7.3
- Deviseのインストールが完了していて、ユーザーの新規登録やログインができる状態。
- 投稿機能が実装済み(モデル、コントローラ含め)
モデルを作成しよう
raisl g model Like user_id:integer post_id:integer
"post_id"は投稿(画像含む)に関するID
モデルに記述しよう
class Like < ApplicationRecord
belongs_to :user
belongs_to :post
end
このアソシエーションのおかげで、以下のような操作が可能になります。
Likeオブジェクトから、関連するUserオブジェクトやPostオブジェクトにアクセスできます。例えば、like.userやlike.postのように書くことができます。
UserオブジェクトやPostオブジェクトから、関連するLikeオブジェクトにアクセスできます。例えば、user.likesやpost.likesのように書くことができます。
class User < ApplicationRecord
has_many :likes, dependent: :destroy #追記
end
class Post < ApplicationRecord
has_many :likes, dependent: :destroy #追記
def liked_by(user) #追記
likes.exsits?(user_id: user.id)
end
end
liked_byメソッドは、liked_byメソッドが引数として与えられたuserオブジェクトが、特定のオブジェクト(たとえば、Post)に対して「いいね」をしているかどうかを判断するためのメソッドです。
likes.exists?(user_id: user.id)は、likesの中でuser_idが引数で渡されたuserのidと一致するものが存在するかどうかを確認しています。存在する場合はtrueを、存在しない場合はfalseを返します。
このメソッドを使用することで、特定のユーザーが特定の投稿に「いいね」をしているかどうかを簡単に判断できます。例えば、以下のように書くことができます。
if post.liked_by(current_user)
# いいねしている場合の処理
else
# いいねしていない場合の処理
end
このメソッドを使って、いいねの状態に応じてビューの表示を変えることができる。
コントローラを作成しよう
rails g controller likes
コントローラに記述しよう
class LikesController < ApplicationController
def create
post = Post.find(params[:post_id])
likes = current_user.likes.new(post_id: post.id)
likes.save
redirect_to posts_path(post)
end
def destroy
post = Post.find(params[:post_id])
like = current_user.likes.find_by(post_id: post.id)
if like.destroy
render json: { status: 'success'}
else
render json: { status: 'error' }
end
end
end
記述の説明をします。
- createアクションは新しいいいねを作成するために使われます
- params[:id]からいいねをつける対象の投稿(post)を探し"post"変数に格納します
- 現在のユーザー(current_user)に紐ずく新しいいいね(Like)オブジェクトを作成、"post_id"を作成して"likes"変数に格納
- "likes.save"で新しいいいねをDBに保存
- 最後に投稿の一覧画面にリダイレクトする
_____________________________________________ - destroyアクションはいいねを削除するために使われます
- params[:post_id]から、いいねを削除する対象の投稿(Post)を見つけて、"post"変数に格納します。
- 現在のユーザー(current_user)が対象の投稿につけたいいね(Like)オブジェクトを探し"like"変数に格納します
- "like.destroy"でいいねをDBから削除します。成功した場合は"JSON"形式で"success"をかえし、失敗した場合は"error"を返します。
JSON形式(レスポンス)とは
JSONレスポンスとは、Webサーバーがクライアント(通常はブラウザ)に返すデータ形式の1つで、JSON(JavaScript Object Notation)という軽量なデータ交換フォーマットを使用しています。JSONはテキストベースの形式で、データ構造を表現するためにオブジェクト(キーと値のペア)と配列を使用します。
JSONレスポンスは、主に非同期通信(Ajax)でWebアプリケーションとサーバー間でデータをやり取りする際に使用されます。JSON形式はJavaScriptで簡単に扱えるため、Webアプリケーションの開発でよく利用されています。
ルーティング設定
Rails.application.routes.draw do
resources :likes, only:[:create, :destroy]
end
jQueryを使える様にしよう
gem "jquery-rails" #追加
いつも通り、、、
bundle install
続いて"config/webpack/environment.js"に記述
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery',
})
)
次に"app/javascript/packs/application.js"に記述
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery")
import "../stylesheets/application"
"app/javascript/packs/likes.js"に記述
$(function() {
// いいねボタンがクリックされたら
$('body').on('click', '.fa-heart', function(){
#現在の状態を取得
var active = $(this).hasClass('active');
#いいねの数の要素を取得
var count = $(this).siblings('.like-count');
#いいねの数を取得
var currentCount = parseInt(count.text());
#いいねの数を更新
count.text(active ? currentCount - 1 : currentCount + 1);
#ハートマークの状態を更新
$(this).toggleClass('active');
#いいねが成功したら
$.ajax({
url: $(this).data('url'),
type: active ? 'DELETE' : 'POST',
dataType: 'json',
data: {'_method': active ? 'DELETE' : 'POST'}
})
.done(function(data) {
console.log(data);
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});
#ボタンのデフォルト動作を無効化
return false;
});
});
ビューに記述
<p>
<% if current_user.liked_posts.include?(post) %>
<% like = current_user.likes.find_by(post: post) %>
<i class="fas fa-heart active" data-url="<%= post_like_path(post, like) %>"></i>
<% else %>
<i class="fas fa-heart" data-url="<%= post_likes_path(post) %>"></i>
<% end %>
<span class="like-count"><%= post.likes.count %></span>
</p>
#FontAwesome使ってます
<% if current_user.liked_posts.include?(post) %>:
現在のユーザー(current_user)が、表示中の投稿(post)に「いいね」をしているかどうかをチェックしています。liked_postsは、ユーザーが「いいね」した投稿のリストを返すメソッドです。include?(post)は、そのリストに表示中の投稿が含まれているかどうかを確認します。含まれている場合は、このブロック内のコードが実行されます。
<% like = current_user.likes.find_by(post: post) %>:
現在のユーザーが投稿に対して作成した「いいね」オブジェクトを取得して、like変数に格納します。
"post_like_path(post, like)"が設定され、いいねの解除に必要なURLが格納されます。
"post_likes_path(post)"が設定され、いいねの作成に必要なURLが格納されます。
"post.likes.count"は、投稿に関連付けられた「いいね」の数を返します。
いいねにアニメーションをつけてみよう
// いいね、アニメーション
/* ハートマーク */
.fa-heart {
color: gray;
cursor: pointer;
}
/* ハートマークホバー時 */
.fa-heart:hover {
color: pink;
}
/* ハートマーククリック時 */
.fa-heart.active {
color: pink;
animation: heart-beat 0.5s;
}
/* いいね数 */
.like-count {
margin-left: 5px;
font-size: 12px;
}
/* アニメーション */
@keyframes heart-beat {
0% {
transform: scale(1);
}
25% {
transform: scale(1.3);
}
50% {
transform: scale(1);
}
75% {
transform: scale(1.2);
}
100% {
transform: scale(1);
}
}
以上で実装の完成です!!
コメント、いいねお待ちしてます👻