LoginSignup
1
1

More than 3 years have passed since last update.

ajaxを用いて、イイねを押した段階でのリアルタイムなイイねの数を表示する。

Last updated at Posted at 2019-07-12

概要

TECH::EXPERTのカリキュラムでオリジナルのミニアプリを作成する機会があり、
その一部のページでイイね機能を実装しました。
発表時のイイねのカウントはAjaxでリクエストを送ってなく、
アイコンをlink_toでネストさせ、コントローラーを動かし、
jQueryで表示のイイね数+1にしてました。

イイねを押した瞬間の総イイね数を表示する
(例えば、ビューをみている間に誰かが同じtweetをイイねして、
ビューに表示されるイイね数が変動する場合)
とともに、ajaxでコントローラーにリクエスト
を送るようにしたので、紹介したいと思います。

作成する前提

MaterializecssがCDNで読み込めている(アイコンに使用してます)
Likeモデルにuser_idとtweet_idのカラムがある
Likesコントローラーがある

編集するファイル

・ビューファイル
・ルートファイル
・コントローラーファイル
・jsファイル

ビューファイル

_tweet.html.erb
        <% if user_signed_in? %>
          <% if Like.find_by(user_id: current_user.id, tweet_id: tweet.id) %>
              <button class="like-button like" ><i class="material-icons middle-size ">favorite</i></button>
          <% else %>
              <button class ="unlike-button like"><i class="material-icons middle-size ">favorite_border</i></button>
          <% end %>
          <a class="like like_count" data-tweet="<%= tweet.id%>"><%= likes_count(tweet) %></a>
        <%end%>

この_tweet.html.erbはshowアクション・indexアクションのビューで共用するので部分テンプレート化してます。
Likeモデルにログインユーザーのidとtweetのidのペアがあれば、既にイイねされてるボタンなければ、その逆を表示させます。
likes.count(tweet)はapplication_html.rbに記載して少しビューの見通しを良くしました。

ルートファイル

route.rb
  get "likes/:tweet_id/create" => "likes#create"
  get  "likes/:tweet_id/destroy" => "likes#destroy"

ajaxを使用するので、getかpostで。
deleteは使えません。

コントローラーファイル

likes_controller.rb
class LikesController < ApplicationController

  before_action :authenticate_user!

  def create
    @like=Like.where(user_id: current_user.id, tweet_id: params[:id])
    Like.create(user_id: current_user.id,tweet_id: params[:id])     if @like.length==0
    @likes=Like.where(tweet_id: params[:id])
    respond_to do |format|
      format.html { redirect_to :root }
      format.json { render json: @likes}
    end
  end

  def destroy
    @like=Like.find_by(user_id: current_user.id,tweet_id: params[:id])
    @like.destroy
    @likes=Like.where(tweet_id: params[:id])
    respond_to do |format|
      format.html { redirect_to :root }
      format.json { render json: @likes}
    end
  end

end

current_userを使用するので、before_action :authenticate_user!
を最初に記載します。
多重押しを制御するため、if @like.lengthにしてます。

jsファイル

like.js
$(function(){
  $(document).on('click','.unlike-button',function(e){
    e.preventDefault();
    var tweet_id=Number($(this).next().data('tweet'))
    var url=$(this).attr('href')
    var html=`<button class="like-button like">
    <i class="material-icons middle-size ">favorite</i>
    </button>`
    $.ajax({
      type:'get',
      url:'/likes/'+ tweet_id + '/create',
      data:{id: tweet_id},
      dataType:'json'
    })
    .done(function(likes){
      var target="a[data-tweet="+ tweet_id +"]"
      $(target).prev().remove()
      $(target).parent().prepend(html)
      $(target).text(likes.length)
    })
    .fail(function(){
      alert('失敗しました')
    })
  })

  $(document).on('click','.like-button',function(e){
    e.preventDefault();
    var count= Number($(this).next().text())
    var tweet_id= Number($(this).next().data('tweet'))
    var url=$(this).attr('href')
    var html=`<button class="unlike-button like">
    <i class="material-icons middle-size ">favorite_border</i>
    </button>`
    $.ajax({
      type:'get',
      url:'/likes/'+ tweet_id + '/destroy',
      data:{id: tweet_id},
      dataType:'json'
    })
    .done(function(likes){
      var target="a[data-tweet="+ tweet_id +"]"
      $(target).prev().remove()
      $(target).parent().prepend(html)
      $(target).text(likes.length)
    })
    .fail(function(){
      alert('失敗しました')
    })
  })
})

特に奇抜なことはぜず、オーソドックスなajaxでデータを送信・受け取りをしました。
イイねのカウントを押した段階でのリアルタイムなカウントにするため、コントローラーで送信した@likes
をlengthメソッドを使用して表記してます。
少し、悩んだのは、カスタムデータ属性のdata-tweetの値を取得する部分です。変数を用いているので
’+’で繋げてあげます。

完成!!

Image from Gyazo

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