LoginSignup
7
5

More than 3 years have passed since last update.

Rails いいね機能の実装

Last updated at Posted at 2019-05-25

Rails + ajax でコメントにいいねする機能をつくったのでまとめます。

参考:railsとjsを使ったお手軽「いいね♡機能」
Railsでいいね機能を実装。Ajaxを使い非同期対応。で

✴️私の場合ログインしてるユーザーがいいねするわけではなくオープン(誰でもいいねできる)だったので上記記事にかいてあるユーザーとのアソシエーションはありません。
✴️いいねが追加されていくだけで減らす機能はつくっていません。

ファイル構成

├── comments
│   ├── _comment_lists.html.erb
│   ├── _form.html.erb 
│   └── create.js.erb
├── likes
│   ├── _like.html.erb
│   └── create.js
route.rb
resources :comments ,:only => [:create] do
  resources :likes, only: [:create]
end

前提

Commentテーブルにはlikes_countカラム(ここでは)がある
Likeテーブルにはcomment_idカラムがある(アソシエーション)
Likeモデルにcounter_cacheというカウントしてくれるRailsの機能を使う記述をする↓

Like.rb
class Like < ApplicationRecord
  belongs_to :comment, counter_cache: :likes_count
end

コントローラ

CommentsController.rb
class CommentsController < ApplicationController
protect_from_forgery except: :create

  def create
    @comment = Comment.new(comment_params)
    @comment.article_id =  session[:top_id]
    if @comment.save
       @comments = Article.find(session[:top_id]).comments
       @comments = []
       @comments << @comment
       render :comment_lists
     else
       render :comment_lists
    end
  end

  private

  def comment_params
    params.require(:comment).permit(:name, :email, :content, :article_id)
  end

end
LikesController.rb
class LikesController < ApplicationController

  def create
    @comment_id = Comment.find(params[:comment_id])
    session[:comment_id] = @comment_id.id
    @like = Like.create( comment_id: session[:comment_id])
    @likes = Like.where( comment_id: session[:comment_id])
    @comment_id.reload   #ここでリロードしなくてもいいように更新処理してくれてる
  end

end

ajax

コメント一覧をeachでまわしてコメントを一つずつを見ていきます。
renderでlikeのviewまで飛びます。
そのときにパーシャルやローカル変数を渡す際は書き方に決まりがあるので注意。
commentのIDが1の場合("likes_button_<%= comment.id %>")("#likes_button_1")となる

comments/_comment_lists.html.erb
<% if @comments.present? %>
  <% @comments.each_with_index do |comment,i| %>
    <div class="comment_box">
      <div class ="wrap">
        <div class = "wrap-l">
          <div class = "id" id = "id_<%= i+1 %>" ><%= i+1 %></div>
          <%= comment.name %>
        </div>
         <div class = "date"><%= comment.created_at.strftime("%Y/%m/%d %H:%M")%></div>
      </div>
      <div class ="wrap">
        <div class ="content"><%= comment.content %></div>
        <div id="likes_button_<%= comment.id %>">
          <%= render :partial =>'likes/like', :locals => { comment: comment } %>
        </div>
      </div>
    </div>
<% end %>

いいねのviewまで来ました。
ここで使っている変数commentは↑_comment_lists.html.erbで指定したものを使っています。

likes/_like.html.erb
<%= button_to comment_likes_path( :comment_id => comment.id), id: "like-button", remote: true do %>
<div class="btn-social-circle btn-social-circle">
<%= fa_icon("fas star") %>
  <span>
    <%= comment.likes_count %>
  </span>
</div>
<% end %>

likes_controller.rbの一行目にかいてある@comment_id = Comment.find(params[:comment_id])がここでつかわれている
@comment_id1の場合("#likes_button_<%= @comment_id.id %>")("#likes_button_1")となる

likes/create.js
$("#likes_button_<%= @comment_id.id %>").html('<%= j(render :partial =>'like', :locals => { comment: @comment_id }) %>')

_like.html.erbでのcommentの取得の仕方はローカル変数を指定して使えるようにしていて、create.jsではlikes_controller.rbに記述した内容が反映されているようだ。

IDに番号を指定しないと3番目のコメントのいいねボタンを押してもDBにはちゃんと3番目のコメントのいいねに+1した値が入ってるのに見た目上リロードする前の増えたいいねは一番上のコメントのいいねに反映されてしまうので識別しなきゃいけないことに注意だ。

番外編

リプライがあったらリプライを表示、なかったらアラートを表示するっていう仕様について
ajaxの中でRailsの文法を使って条件分岐できます

      $(function () {

    // <!-- リプ一覧欄開閉 -->
      $('#reply_lists_id_<%= i+1 %>').hide();
      <% if comment.replies.present? %>
        $('#comment_user_<%= i+1 %>').click(function () {
          $('#reply_lists_id_<%= i+1 %>').toggle();
      <% else %>
        $('#comment_user_<%= i+1 %>').click(function () {
          window.alert('リプライがありません。');
      <% end %>
      });

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