LoginSignup
0
0

More than 1 year has passed since last update.

【Rails】いいね機能を非同期で実装する手順(jQuery, liked_by?メソッド, FontAwesome)

Last updated at Posted at 2022-12-11

概要

ユーザーが任意のitemに対していいね!(非同期通信)ができるように実装したので、その手順をここに残しておく。

前提

  • deviseによるログイン機能が実装できている。
  • いいね!機能は、非同期通信で行う。liked_by?とJQueryで実践する。
  • index(トップページ)に表示されているitemのいいね!ボタンをクリックできる。
  • 一人のユーザーは、一つのitemに対して、いいね!を1回までしか押せない。
  • 自分がすでにいいね!済みならそれを消すことができる。
  • いいね!したitem一覧はユーザーのマイページから一覧で見ることができる。
  • テーブルやカラムの関連性は以下データベースと後述のアソシエーションを参照。

データベース設計

image.png

jQuery導入

  • JQuery導入:yarn add jqueryを実行

    • Rails5以前の導入方法ではjquery-railsというGemをインストールするのが基本のよう
    • 今回はWebpackerで管理するのでyarnコマンドを使用してインストール
    • エラーUncaught ReferenceError: $ is not definedは実装失敗に出る
  • 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'
  })
)
  • application.jsでjQueryを呼び出せるようにするため、application.jsに以下を追加
app/javascript/packs/application.js
require("jquery") 

それぞれのモデルのアソシエーションを設定

  • アソシエーションの関係性は以下の通り
    • UsersとLikesは一体多の関係性(Userは複数のいいね!をできるため)
    • ItemsとLikesも一体多の関係性(Itemは複数のいいね!を持つため)
  • user.rbに以下を記載
    • liked_by?メソッドを作成。whereメソッドを使用し、likesテーブルにitem_idが存在しているかどうか検索をかけ、存在していなければいいね!・存在していればいいね!を解除するという条件分岐のメソッド。
app/models/user.rb
has_many :reviews, dependent: :destroy
has_many :likes, dependent: :destroy

def liked_by?(item_id)
  likes.where(item_id: item_id).exists?
end
  • likeモデルに以下を記載
app/models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :item
end
  • itemモデルに以下を記載
app/models/item.rb
class Item < ApplicationRecord
  has_many :reviews, dependent: :destroy
  has_many :likes, dependent: :destroy
end
  • migrateでlikeを追加
db/migrate/20220516123542_create_likes.rb
class CreateLikes < ActiveRecord::Migration[6.0]
  def change
    create_table :likes do |t|
      t.integer :user_id, null: false
      t.integer :item_id, null: false
      t.timestamps
    end
  end
end

ルーティングを設定

  • いいね!をつけるcreateアクションをpostメソッド、いいね!を外すdestroyアクションをdeleteメソッドを使ってルーティングを記述する
  • オプションでas:を記述することでPrefixの名前を指定できる
config/routes.rb
 post 'like/:id' => 'likes#create', as: 'create_like'
 delete 'like/:id' => 'likes#destroy', as: 'destroy_like'

  • idが必要なため、memberを使用。以下を追記
config/routes.rb
resources :users do
    member do
      get :likes
    end
  end

controllerを設定(いいね!をcreate・destroyする設定を行う)

  • likes_controllerを作成、以下を記載。
    • itemのidを取得するためbefore_actionitem_paramsというメソッドを実行させる。ビューに定義する@itemというインスタンス変数を使用し、非同期通信でビューにデータを反映させるため。
app/controllers/likes_controller.rb
class LikesController < ApplicationController
  before_action :item_params
  def create
    Like.create(user_id: current_user.id, item_id: params[:id])
  end

  def destroy
    Like.find_by(user_id: current_user.id, item_id: params[:id]).destroy
  end

  private

  def item_params
    @item = Item.find(params[:id])
  end
end
  • users_controllerにて、いいねした投稿を探し、@like_itemsに格納。これはマイページのいいね!一覧で利用する(後述)
    • pluckメソッドは、特定のカラムの値だけ取得したい場合に使える
app/controllers/users_controller.rb
 def likes
    @user = User.find(params[:id])
    likes = Like.where(user_id: @user.id).pluck(:item_id)
    @like_items = Item.find(likes)
  end

ビューを編集

  • いいね!をつける場合・いいね!を消す場合の方法は以下の通り
    • ユーザーがサインインしていれば、いいねを押すことが出来るようにするので、<% if user_signed_in? %>と記述する
    • <% if current_user.liked_by?(item.id) %>でliked_by?メソッドを呼び出し、いいねの有無を判別
    • 今回は部分テンプレートでlike.htmlを作っているのでそこに記載しているが、index.htmlでも問題ない
app/views/likes/_like.html.erb
<% if user_signed_in? %>
 <% if current_user.liked_by?(item.id) %>
   <td>
    <%# いいね!を消す場合 %>
   <%= link_to destroy_like_path(item), method: :DELETE, remote: true do %>
   <i class="fa fa-heart unlike-btn">お気に入り!</i>
     <% end %>
      </td>
 <% else %>
   <td>
    <%# いいね!をつける場合 %>
   <%= link_to create_like_path(item), method: :POST, remote: true do %>
      <i class="fa fa-heart like-btn">お気に入り!</i>
         <% end %> 
    </td>
 <% end %>
<% end %>
  • 部分テンプレートを利用する場合は、index.htmlには以下のように記載する。idを付与することにより、どのitemに対していいねが押されたのかを判別し、HTMLを切り替えられるようにする。
<div id="likes_buttons_<%= item.id %>">
 <%= render partial: 'likes/like', locals: {item: item} %>
</div>
  • 非同期いいねでは、link_toのオプションにremote: trueが必須。これにより、js.erbファイルを呼び出し、ページ遷移を行わない非同期通信が可能になる。ちなみに作成したjsファイルの中身とディレクトリは以下
    • コントローラーで指定したアクションと同じ名前で.js.erbファイルを作ること
app/views/likes/create.js.erb
$('#likes_buttons_<%= @item.id %>').html("<%= j(render partial: 'likes/like', locals: {item: @item}) %>");
app/views/likes/destroy.js.erb
$('#likes_buttons_<%= @item.id %>').html("<%= j(render partial: 'likes/like', locals: {item: @item}) %>");
  • ユーザーのマイページに「いいね!したitem一覧を見る」ボタンを設置。CSSは任意。
app/views/users/show.html.erb
<a class="btn btn--orange btn--radius" href= <%= likes_user_path(@user) %>>いいね!した一覧を見る</a>
  • なお、Railsでは、一般的にlink_toメソッドを使用するので、以下のようにすることが多いかも
app/views/users/show.html.erb
<%= link_to "いいね!した一覧を見る", likes_user_path(@user), class: btn btn--orange btn--radius %>
  • 「いいね!したitem一覧」を表示させる。users_controller.rbで設定した@like_itemsの中身をeach文により表示させる。
app/views/users/likes.html.erb
<div class="box-title"> いいね!したitem一覧</div>
 <% @like_items.each do |item|%>
  <ul>
   <a class="btn btn-radius-solid2" href= <%= item_path(item.id) %>><%= item.item_name %><i class="fas fa-angle-right fa-position-right"></i></a>
  </ul>
 <% end %>
</div>

FontAwesomeでハートマークにする

  • 以下をapplication.html.erbのheadタグ内に追記
app/views/layouts/application.html.erb
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.13.0/css/all.css" integrity="sha384-Bfad6CLCknfcloXFOyFnlgtENryhrpZCe29RTifKEixXQZ38WheV+i/6YWSzkz3V" crossorigin="anonymous">
 </head>
  • ビューで以下のように記載
app/views/likes/_like.html.erb
<i class="fa fa-heart like-btn">お気に入り!</i>
<i class="fa fa-heart unlike-btn">お気に入り!</i>
# ほか省略
  • CSSは以下で設定可能
app/assets/stylesheets/likes.scss
.like-btn {
  font-size: 15px;
  color: #808080;
 }
 
 .unlike-btn {
  font-size: 15px;
  color: #e54747;
 }

ソースコードはこちら

参考記事

erbファイルのマークダウンについて

  • まったく関係ない話ですが、qiitaでerbファイルのソースコードをマークダウン表記する場合、ファイル名をerb:index.html.erbとしなければハイライトされません。.erbだけで適応されると良いのですが(-_-;)
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