記事概要
Ruby on Railsにいいね機能を実装する方法について、まとめる
前提
- Ruby on Railsでアプリケーションを作成している
サンプルアプリ(GitHub)
いいね機能
仕組み
ユーザーが好みのツイートに印をつけられる機能
いいねするユーザーといいねされるツイートは多対多の関係
ER図
手順1(必要なモデルを作成)
- Likeモデルを作成する
% rails g model like
- 必要なカラムを追加するため、マイグレーションファイルを編集する
db/migrate/20XXXXXXX_create_likes.rb
class CreateLikes < ActiveRecord::Migration[7.1] def change create_table :likes do |t| t.references :user, foreign_key: true t.references :tweet, foreign_key: true t.timestamps end end end
- 下記コマンドを実行する
% rails db:migrate
手順2(アソシエーションを設定)
- Likeモデルを編集する
app/model/like.rb
class Like < ApplicationRecord belongs_to :user belongs_to :tweet end
- Tweetモデルを編集する
app/model/tweet.rb
# 省略 has_many :likes end
- Userモデルを編集する
app/model/user.rb
# 省略 has_many :likes end
手順3(ルーティングを設定)
- likesコントローラーのcreateアクション、destroyアクションを動作させるためのルーティングを設定する
config/routes.rb
Rails.application.routes.draw do devise_for :users root to: 'tweets#index' resources :tweets, only: [:index, :new, :create] do # createアクションは「いいねする処理」、destroyアクションは「いいねを解除する処理」 resource :likes, only: [:create, :destroy] end resources :users, only: [:show] end
手順4(いいね済かを判定するメソッドを作成)
- Tweetモデルにメソッドを定義する
app/model/tweet.rb
# 省略 # ユーザーが該当ツイートをいいね済かどうかを判定するメソッド def liked_by?(user) likes.where(user_id: user.id).exists? end end
手順5(いいねボタンを作成)
- いいねボタンを作成するため、
app/views/tweets/_tweet.html.erb
を編集する※いいねボタンのブロック要素を<div class="tweet"> <p class = "tweet-text"><%= tweet.text %></p> <div class="tweet-name"> <%= link_to "投稿者:#{tweet.user.name}", user_path(tweet.user)%> </div> <%#= いいねボタン %> <div id="like-btn<%= tweet.id %>"> <% if user_signed_in? && tweet.liked_by?(current_user)%> <%=link_to "いいね済", tweet_likes_path(tweet.id), data: { turbo_method: :delete }, class: "tweet_likes" %> <% else %> <%=link_to "いいねする", tweet_likes_path(tweet.id), data: { turbo_method: :post }, class: "tweet_likes" %> <% end %> </div> </div>
class
ではなくid
としている理由は、いいね機能を非同期化するときに、どのいいねボタンが押されたかを区別する必要があるため - いいねボタンが表示されることを、ブラウザで確認する
手順6(コントローラーを作成)
- likesコントローラーを作成する
% rails g controller likes
- create、destroyアクションを定義する
app/controllers/likes_controller.rb
class LikesController < ApplicationController def create like = current_user.likes.build(tweet_id: params[:tweet_id]) like.save redirect_to root_path end def destroy like = Like.find_by(tweet_id: params[:tweet_id], user_id: current_user.id) like.destroy redirect_to root_path end end
- いいねボタンを部分テンプレートに切り出す
-
app/views/likes/_like.html.erb
を手動作成する -
_like.html.erb
を編集する<% if user_signed_in? && tweet.liked_by?(current_user)%> <%=link_to "いいね済", tweet_likes_path(tweet.id), data: { turbo_method: :delete }, class: "tweet_likes" %> <% else %> <%=link_to "いいねする", tweet_likes_path(tweet.id), data: { turbo_method: :post }, class: "tweet_likes" %> <% end %>
- 部分テンプレートを呼び出すため、
app/views/tweets/_tweet.html.erb
を編集する<%#= 省略 %> <%#= いいねボタン %> <div id="like-btn<%= tweet.id %>"> <%= render partial: "likes/like", locals: { tweet: tweet } %> </div> </div>
-
- 「いいね」をクリックした際に、リロードされないことをブラウザで確認する
- 「いいね済」をクリックした際に、リロードされないことをブラウザで確認する