LoginSignup
0
0

More than 1 year has passed since last update.

Rails いいね機能実装(非同期通信)

Posted at

はじめに

今回はSNSアプリでデフォルトと言っていいほど備わっている機能(いいね)の実装方法について記載します。

開発環境、前提条件

  • AWS Cloud9
  • Ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
  • Rails 6.1.7.3
  • Deviseのインストールが完了していて、ユーザーの新規登録やログインができる状態。
  • 投稿機能が実装済み(モデル、コントローラ含め)

モデルを作成しよう

~/environment
raisl g model Like user_id:integer post_id:integer

"post_id"は投稿(画像含む)に関するID

モデルに記述しよう

models/like.rb
class Like < ApplicationRecord

  belongs_to :user
  belongs_to :post
end

このアソシエーションのおかげで、以下のような操作が可能になります。

Likeオブジェクトから、関連するUserオブジェクトやPostオブジェクトにアクセスできます。例えば、like.userやlike.postのように書くことができます。
UserオブジェクトやPostオブジェクトから、関連するLikeオブジェクトにアクセスできます。例えば、user.likesやpost.likesのように書くことができます。

models/user.rb
class User < ApplicationRecord
has_many :likes, dependent: :destroy #追記
end
models/post.rb
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を返します。

このメソッドを使用することで、特定のユーザーが特定の投稿に「いいね」をしているかどうかを簡単に判断できます。例えば、以下のように書くことができます。

views.html.erb
if post.liked_by(current_user)
  # いいねしている場合の処理
else
  # いいねしていない場合の処理
end

このメソッドを使って、いいねの状態に応じてビューの表示を変えることができる。

コントローラを作成しよう

~/environment
rails g controller likes

コントローラに記述しよう

controller/likes.rb
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アプリケーションの開発でよく利用されています。

ルーティング設定

config/routes.rb
Rails.application.routes.draw do

resources  :likes, only:[:create, :destroy]

end

jQueryを使える様にしよう

Gemfile
gem "jquery-rails" #追加

いつも通り、、、

~/environment
bundle install

続いて"config/webpack/environment.js"に記述

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"に記述

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"に記述

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;
  });
});

ビューに記述

app/viwes/posts/_likes.html.erb
<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"は、投稿に関連付けられた「いいね」の数を返します。

いいねにアニメーションをつけてみよう

app/assets/stylesheets/application.scss
// いいね、アニメーション

/* ハートマーク */
.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);
  }
}

以上で実装の完成です!!
コメント、いいねお待ちしてます👻

0
0
0

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
0
0