railsとjsを使ったお手軽「いいね♡機能」

  • 93
    いいね
  • 15
    コメント

はじめに

プログラミング初心者の皆さんこんにちは!(こちらの記事はプログラミング初心者を対象に書いています。)

今回はjavascriptをあまり書いたことのない初心者の方でも簡単につくれるrailsとjavascriptを使った「いいね(like)機能」を実装していこうと思います。
基本的なrailsの説明は省いています。

今回はrailsのひとつ完成したアプリケーションがあるとしてそこに「いいね機能」を付け足すという流れで進めていきます。
今回は例として、ツイッターのようなSNSアプリに他人のツイートにいいねできるような機能を追加していこうと思います。
なのでtweet、userモデルとtweetsコントローラーがある前提で話を進めていきます。
一つのツイートに対して一人のユーザーがいいねできるのは一回までで、ツイッターのように灰色のハートを押すといいね(createアクション)、既にいいねされている赤のハートを押すといいねを取り消すこと(destroyアクション)ができます。

likesテーブルを作成しよう

ターミナルでlikesテーブルを作成しましょう。カラムはinteger型でuser_idとtweet_idを追加しておきましょう。
モデルファイルに以下を記述。

models/like.rb
class Like < ActiveRecord::Base
  belongs_to :tweet, counter_cache: :likes_count
  belongs_to :user
end

counter_cahce: :likes_countはリレーションされているlikeの数の値をリレーション先のlikes_countというカラムの値に入れますよって意味です。なのでlikes_countカラムをtweetsテーブルに追加しましょう。

tweetsテーブルにlikes_countカラムを追加しよう

tweetsテーブルにinteger型のlikes_countというカラムを追加しましょう。
さらに同モデルファイルに以下の記述を追加しましょう。

tweet.rb
class Tweet < ActiveRecord::Base
  has_many :likes, dependent: :destroy
  def like_user(user_id)
   likes.find_by(user_id: user_id)
  end
end

like_userメソッドは後に取り扱いますが、端的にいうとそのユーザーが既にツイートにいいねしているかどうか確認するメソッドです。

ルーティングを記述しよう

tweetsとlikesはネスト構造をとっています。resourcesを使いながら記述しましょう。

routes.rb
Rails.application.routes.draw do
  resources :tweets do
    resources :likes, only: [:create, :destroy]
  end
end

アクションを定義しましょう

まずはlikes controllerを作成しましょう。作成したらそのファイルに以下を記述しましょう

likes_controller.rb
class LikesController < ApplicationController
  def create
    @like = Like.create(user_id: current_user.id, tweet_id: params[:tweet_id])
    @likes = Like.where(tweet_id: params[:tweet_id])
    @tweets = Tweet.all
  end

  def destroy
    like = Like.find_by(user_id: current_user.id, tweet_id: params[:tweet_id])
    like.destroy
    @likes = Like.where(tweet_id: params[:tweet_id])
    @tweets = Tweet.all
  end
end

いいね(like)を増やすcreateアクションもdestroyアクションも同じで増やすたり消したりするlikeとそのあとの合計いいね数を表示するための@likes、とその後、tweetの一覧ページを表示するための@tweetsが定義されています。(ここでは説明を簡潔にしたいので記述を最低限におさえています。)

部分テンプレートを作ろう

今回はいいねボタンを部分テンプレートを使って作ります。
ユーザーがサインインしていない状態では押しても何も反応しないハートを表示します。ユーザーがサインインしているときは先ほど定義したlike_userメソッドを使いながら、そのユーザーがツイートにいいねしているかどうか判断しながら、表示を切り分けます。
ちなみに先ほど、likesのモデルファイルでcounter_cacheの記述を書いているので、tweet.like_countとするだけでそのツイートに結びつくlike数が表示されます。
どちらのアクションのパスもremote: trueの記述をしてajaxを使いながらアクションを実行します。
icon_red_heard.svgがいいね後の赤いハート、
icon_heart.svgがいいね前の灰色のハートととしてます。

_like.html.erb
<% if user_signed_in? %>
  <% if tweet.like_user(current_user.id) %>
    <%= button_to tweet_like_path(like, tweet_id: tweet.id), method: :delete, id: "like-button", remote: true do %>
      <%= image_tag("icon_red_heart.svg") %>
      <span>
        <%= tweet.like_count %>
      </span>
    <% end %>
  <% else %>
    <%= button_to tweet_likes_path(tweet), id: "like-button", remote: true do %>
      <%= image_tag("icon_heart.svg") %>
      <span>
        <%= tweet.like_count %>
      </span>
    <% end %>
  <% end %>
<% else %>
  <% = image_tag("icon_heart.svg") %>
    <span>
      <%= tweet.like_count %>
    </span>
<% end %>

JSファイルを作ろう

いよいよjsを書く時がやって来ました。
ajaxを使ったページ遷移をせずにいいねを増やしたり消したりするjavascriptファイルを作りましょう。

views/likes/create.js.erb
$("#like-buttons").html("<%= j(render partial: 'like', locals: { tweets: @tweets, likes: @likes, like: @like}) %>")

views/likes/destroy.js.erb
$("#like-buttons").html("<%= j(render partial: 'like', locals: { tweets: @tweets, likes: @likes }) %>");

以上です。なんとjsを書くのはたったこれだけなんですね。なので今回のいいね機能はrailsの基本を押さえている方なら、多分すぐ出来てしまいます。簡単かつ普通に動くので他にもやり方は色々ありますが、このやり方は特におすすめです。

この投稿は TECH::CAMP Advent Calendar 20158日目の記事です。