5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails x Ajaxで「お気に入り」をオンオフできるリストを作成する

Last updated at Posted at 2018-10-14

はじめに

  • こんな感じのAjaxで「お気に入り」のオンオフできる(ついでにカウントも)リストを作ります。
  • Deviseを使ってログインしている状態を想定しているので、Deviseをある程度知っている人向けです。

今回使うライブラリ

必要な予備知識

  1. RailsのAjax通信。
  2. BootStrap4(ビューの整形に使っているだけなので、詳しくなくていい)
  3. Slimテンプレート(2と同様)
  4. 使われているライブラリの知識

環境

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]

$ rails -v
Rails 5.2.1

実装

モデル

  • 今回はUserDogLikeモデルを使います。
  • UserモデルはDeviseで作成します。
  • Likeを中間テーブルとして、UserDogを多対多の関連づけすることで、いいねリレーションを構築します。
  • seed-fuとかを使って、前もってページネーション用のインスタンスをDBに作っておきましょう。
# マイグレーション
class CreateDogs < ActiveRecord::Migration[5.2]
  def change
    create_table :dogs do |t|
      t.string :name, null: false, default: ''
      t.integer :receive_likes_count, null: false, default: 0
    end
  end
end

class CreateLikes < ActiveRecord::Migration[5.2]
  def change
    create_table :likes do |t|
      t.references :user
      t.references :dog
    end
  end
end
class User < ApplicationRecord
  has_many :likes, dependent: :destroy
end

class Dog < ApplicationRecord
  has_many :receive_likes, dependent: :destroy, class_name: 'Like'

  # 特定のユーザーからお気に入りされているか
  def liked_by?(user)
    user.likes.exists?(dog_id: id)
  end

  # Ajax実行時に、DOMエレメントを特定するID
  def id_attribute
    "dog-#{id}"
  end
end

class Like < ApplicationRecord
  belongs_to :user
  belongs_to :dog
  # counter culture設定
  counter_culture :dog, column_name: 'receive_likes_count'
end

コントローラー

  • 今回のページをsample#indexアクションとします。
  • 「いいね」しても順番が表示の順番が変わらないよう、orderを設定しておきます。
class SampleController < ApplicationController
  def index
    @dogs = Dog.all.order(created_at: :asc) 
  end
end
  • また、いいねをAjaxでオンオフするためのAPIコントローラーapi/like_controller.rbも追加します。
  • このコントローラー呼び出し時に実行されるJSファイルは後ほど記載します。
class Api::LikeController < ApplicationController
  before_action :setup_dog!
  before_action :setup_like!

  def create
    @like.save
  end

  def destroy
    @like.destroy
  end

  private

  def setup_dog!
    @dog = Dog.find(params[:dog_id])
  end

  def setup_like!
    # create時はまだ存在していないのでinitializeされ、
    # destroy時は既に存在しているのでfindされる。
    @like = current_user
              .likes
              .find_or_initialize_by(dog_id: @dog.id)
  end
end
  • ルーティングはこんな感じ。
namespace :api do
  post 'like/:dog_id' => 'like#create', as: :like
  delete 'like/:dog_id' => 'like#destroy', as: :unlike
end

ヘルパー

  • いいねをオンオフするボタンをレンダーするヘルパーメソッドを作成する。
  • これにより、ログイン中のユーザーが特定のDogモデルをお気に入りしたかどうかを判定して、アイコンとリンクを出し分けることができる。
module MyHelper
  def toggle_like_button(dog)
    # ログインしていない場合
    return fa_icon 'heart-o', text: dog.receive_likes_count if current_user.blank?

    liked = dog.liked_by?(current_user)
    icon = fa_icon (liked ? 'heart' : 'heart-o'), text: dog.reload.receive_likes_count
    if liked
      # お気に入りを外すボタン
      link_to icon, api_unlike_path(dog_id: dog.id), remote: true, method: :delete
    else
      # お気に入りするボタン
      link_to icon, api_like_path(dog_id: dog.id), remote: true, method: :post
    end
  end
end

ビュー

  • 今回用意するビューは、大元のページ用と、Dogのパーシャルビューの2つです。
# ページ
app/views/sample/
├── _dog.html.slim
└── index.html.slim
/ index.html.slim
.container.my-5
  .row
    .col-md-6.offset-md-3
      #project-list(style='overflow-y: scroll; height: 80vh;')
        = render @dogs
/ _dog.html.slim
.card.card-body.mb-3(id="#{dog.id_attribute}")
  / この.like要素をAjaxで書き換える
  .like
    = toggle_like_button(dog)
  h3.card-title = dog.name

JSファイル

  • 最後にlikeコントローラー呼び出し時に呼び出されるJSファイルを追加します。
app/views/api/like/
├── create.js.erb
└── destroy.js.erb
// create.js.erb

// toastrの通知処理
toastr.success("<%= "#{@like.dog.name}をお気に入りに追加しました" %>")
// 特定のLIKEボタンのDOMを入れ替える。
$("<%= "##{@dog.id_attribute} .like" %>").html("<%= j toggle_like_badge(@dog) %>") 
// destroy.js.erb

toastr.error("<%= "#{@dog.name}をお気に入りから削除しました" %>")
$("<%= "##{@dog.id_attribute} .like" %>").html("<%= j toggle_like_badge(@dog) %>")

おわりに

  • かけあしでしたが、ひとまずこれで「お気に入り処理」ができるようになりました。
  • いろんな便利なライブラリがあるっていいですね。
5
4
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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?