LoginSignup
1
2

More than 3 years have passed since last update.

【Rails6】いいね機能を実装してみた

Last updated at Posted at 2021-04-29

環境

Rails6.1.3
Ruby3.0.1

同期処理

①モデルを作成

今回はコメントに対するいいねなので、user_idcomment_idと関連付けます

% rails g model Good user_id:integer comment_id:integer

②モデルに関係性を記述

user,commentモデルにそれぞれ以下の記述を追加
dependent: :destroyでユーザーかコメントが消えたときにいいねも消えるようになります

has_many :goods, dependent: :destroy
app/model/good.rb
  belongs_to :user
  belongs_to :comment

③ルーティングの設定

今回は、コメントに対するいいねということなので、ルーティングがネスト化されます
また、いいねは作るか消すかだけなので、onlyも書いておきます

config/routes.rb
  resources :comments do
    resources :goods, only: %i[create destroy]
  end

④controllerの編集

createdestroyについてメソッドを書きます
いいねをするのは、current_userなので、current_user.idからuser_idを取得します

app/controller/goods_controller.rb
class GoodsController < ApplicationController

  def create
    @good = Good.create(user_id: current_user.id, comment_id: params[:comment_id])
    @good.save
  end

  def destroy
    @good = Good.find_by(user_id: current_user.id, comment_id: params[:comment_id])
    @good.destroy
  end
end

⑤viewの設定

<% if logged_in? %>でログインしているか判定
<% if current_user.good_user?(comment.id) %>で現在のユーザーがいいねをしているかどうかを判定し、createdestroyか分岐

   <div class="comment_goods">
      <% if logged_in? %>
      <% if current_user.good_user?(comment.id) %>
      <%= link_to comment_good_path(comment.id, current_user.goods.find_by(comment_id: comment.id).id), method: :delete do %>
      <p class="good-button"><i class="far fa-heart like-btn" style="color: #e82a2a;"></i><span style="color: #e82a2a"><%= comment.goods.count %></span></p>
       <% end %>
       <% else %>
       <%= link_to comment_goods_path(comment.id), method: :post do %>
       <p class="good-button"><i class="fas fa-heart unlike-btn" style="color: #e82a2a;"></i><span style="color: #e82a2a"><%= comment.goods.count %></span></p>
       <% end %>
       <% end %>
       <% end %>
   </div>

pathの名前は

% rails routes  

で確認

comment_goods POST   /comments/:comment_id/goods(.:format)                                                             goods#create
comment_good DELETE /comments/:comment_id/goods/:id(.:format)

ここから持ってきます

非同期処理

非同期処理は、Ajax処理とjQueryを利用します。
jQueryの導入方法は、調べたらたくさん出てくるはずなので調べてみてください。
(Railsのバージョンによって方法が変わるので注意!)

①いいね機能部分を部分テンプレート化

app/view/goods/_good.html.erb
<% if current_user.good_user?(comment.id) %>
<%= link_to comment_goods_path((comment.id)), method: :delete, remote: true do %>
<p id="good_<%= comment.id %>"><i class="fas fa-heart unlike-btn" style="color: #e82a2a;"></i><span style="color: #e82a2a"><%= comment.goods.count %></span></p>
<% end %>
<% else %>
<%= link_to comment_goods_path((comment.id)), method: :post, remote: true do %>
<p id="good_<%= comment.id %>"><i class="far fa-heart like-btn" style="color: #e82a2a;"></i><span style="color: #e82a2a"><%= comment.goods.count %></span></p>
<% end %>
<% end %>

Ajax処理で更新させたい部分(今回であればいいねのボタン部分)を部分テンプレート化します。
ここで同期処理⑤のViewからの変更点があります。

remote: true doを追記

remote: true doにすることで、js形式のリクエストを送信することができます。
create.js.erb,destroy.js.erbが発動します。

ボタンのidを変更

id="good_<%= comment.id %>"にすることで、更新されるいいねボタンを限定しています。
これを行わないと、全てのいいねボタンが同時に更新されることになってしまいます。

パスの変更

以下の記事を参考にさせていただきました。
主キーの所得方法で、めちゃくちゃ悩みました、、、

②レンダリング先での表示方法

レンダリング先で使用している変数(今回であればcomment)を部分テンプレートにも渡すために、
locals:{comment:comment}を記載します。

<%= render partial:'goods/good',locals:{comment:comment} %>
app/view/questions/show.html.erb
<% @comments.each do |comment| %>
<% if @question.id == comment.question_id %>
<div class="comment-box">
    <% if comment.user.image? %>
    <%= link_to (image_tag comment.user.image.thumb.to_s),user_path(comment.user.id) %>
    <% else %>
    <%= link_to (image_tag "default.png",class: "q-user-image"), user_path(comment.user.id), method: :get,  alt:"ユーザーアイコン" %>
    <% end %>
    <%= comment.user.name %>
    <%= comment.content %>
    <%= time_ago_in_words(comment.created_at) %><% if logged_in? %>
        <%= render partial:'goods/good',locals:{comment:comment} %>
</div>

③create,destroyのjs処理を追加

いいねボタンが押された時の処理を作成します。
idで指定されたいいねボタンが押されたら、部分テンプレート化されたいいね部分のみ更新する処理になっています。
ここでは、インスタンス変数を使います。

app/view/goods/create.js.erb
$('#good_<%= @comment.id %>').html("<%= j(render partial: 'goods/good', locals: {comment: @comment}) %>");
app/view/goods/destroy.js.erb
$('#good_<%= @comment.id %>').html("<%= j(render partial: 'goods/good', locals: {comment: @comment}) %>");

終わりに

いいね機能の非同期処理を実装する中で、インスタンス変数とローカル変数の違い、resourceとresoursesの違いなど多くの学びがありました。
わかりにくい部分、間違えている部分などありましたらコメントいただけますと幸いです!

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