フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援
フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援

Rails 非同期でいいね機能(Ajax)

はじめに

いいねの非同期の代表格はTwitterですね。
Twitterと同じように投稿に対してのいいね機能を非同期通信を用いて実装します。

実装

Railsの基礎の部分は説明は省き、コマンドのみを下記に記述します。
jQuery, Font Awesomeは各自使えるようにしてください。

$ rails new favorite_ajax

$ cd favorite_ajax

ログイン認証はdeviseを使用。

Gemfile
...(省略)
gem 'devise'
$ bundle install

$ rails g devise:install

$ rails g devise User

投稿機能はscaffoldを使用。

$ rails g scaffold Post title:string user_id:integer

いいねのためのモデルを作成。
カラムはuser_idとpost_id。

$ rails g model Favorite user_id:integer post_id:integer

$ rails db:migrate

ルートへのルーティングを投稿一覧ページにしgetメソッドで/postsにアクセスするボタンを全てroot_pathに変更する。

config/routes.rb
  ...(追加)
  root 'posts#index'

ログインしていない場合とログインページへ遷移

posts_controller.rb
  class PostsController < ApplicationController
    before_action :set_post, only: [:show, :edit, :update, :destroy]
    before_action :authenticate_user!

モデル間の関連付け

user.rb
  ...(追加)
  has_many :posts, dependent: :destroy
  has_many :favorites, dependent: :destroy
post.rb
  ...(追加)
  belongs_to :user
  has_many :favorites, dependent: :destroy

  def favorited_by?(user) #いいねしているかどうか
    favorites.where(user_id: user.id).exists?
  end
favorite.rb
  ...(追加)
  belongs_to :user
  belongs_to :post

投稿時にuser_idカラムにcurrent_user.idを指定

posts_controller.rb
  def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    ...(省略)
  end

投稿一覧ページの投稿のテーブルにいいねボタンを配置(Font Awesomeを使用)

index.html.erb
  <% if post.favorited_by?(current_user) %>
    <td>
      <%= link_to fav_posts_path(post), class: "fav", remote: true do %>
        <i class="fa fa-heart" id="<%= post.id %>"></i>
      <% end %>
    </td>
  <% else %>
    <td>
      <%= link_to fav_posts_path(post), class: "fav", remote: true do %>
        <i class="fa fa-heart-o" id="<%= post.id %>"></i>
      <% end %>
    </td>
  <% end %>

いいねのためのルーティングとアクション追加

config/routes.rb
  ...(追加)
  get 'posts/fav/:id' => 'posts#fav', as: "fav_posts"

Favoritesコントローラにcreateアクションとdestroyアクションを定義しても良いが今回はPostsコントローラにいいねのためのアクションを一つ定義する。

posts_controller.rb
  ...(追加)
  def fav
    post = Post.find(params[:id])
    if post.favorited_by?(current_user)
      fav = current_user.favorites.find_by(post_id: post.id)
      fav.destroy
      render json: post.id
    else
      fav = current_user.favorites.new(post_id: post.id)
      fav.save
      render json: post.id
    end
  end

いいねしている時としていない時のボタンの色を変える

application.css
  ...(追加)
  .fa-heart {
    color: red;
  }

この時点でいいねボタンをクリックすると非同期でいいね、いいねを外す機能が実装できており、
ブラウザをリロードすると色が反映される。
リロードせずに色を反映させたいためapplication.jsにAjax通信が成功した時のイベントを書く。

application.js
  ...(省略)
  $(function() {
    $(document).on("ajax:success", ".fav", function(e) {
      if ($('#' + e.detail[0]).hasClass('fa-heart')) {
        $('#' + e.detail[0]).removeClass('fa-heart').addClass('fa-heart-o');
      } else {
    $('#' + e.detail[0]).removeClass('fa-heart-o').addClass('fa-heart');
      }
    })
  })

サーバーからレスポンスとして返ってくる情報は投稿のidのみ。
ハートアイコン(iタグ)に投稿のidを指定していてその要素がfa-heartクラスを持っていたらfa-heartクラスを消しfa-heart-oクラスをつける。
逆にfa-heart-oクラスを持っていたらfa-heart-oクラスを消しfa-heartクラスをつける。

これで投稿へのいいね機能を非同期で実装できる。

最後に

いいねの数はcountを使えば数を取得できる。
link_toにremote: trueを指定しないと非同期通信はできない。

完成コード

参考サイト

[紹介元] jQueryタグが付けられた新着投稿 – Qiita Rails 非同期でいいね機能(Ajax)

コメント

記事に戻る

コメントを残す