💓

Rails いいね機能

2023/04/19に公開

いいね機能

「いいね機能」のテーブルを設計

カラム名 データ型 カラムの説明
id integer 「いいね」ごとのID
user_id integer 「いいね」したユーザのID
post_image_id integer 「いいね」された投稿画像のID

Model

「Favorite」という名でモデルを作成
ターミナル

rails g model Favorite user_id:integer post_image_id:integer

マイグレーションでテーブルをデータベースへ反映

rails db:migrate

Favoriteモデルのカラムに関連付け

app/models/favorite.rb

 belongs_to :user
 belongs_to :post_image

PostImageモデルに関連付け

app/models/post_image.rb

has_many :favorites, dependent: :destroy
  :

def favorited_by?(user)
   favorites.exists?(user_id: user.id)
end

favorited_by?メソッド

このメソッドで、引数で渡されたユーザidがFavoritesテーブル内に存在(exists?)するかどうかを調べられる!
存在していればtrue、存在していなければfalseを返す。

Userモデルに関連付け

has_many :favorites, dependent: :destroy

Routing

config/routes.rb

resources :post_images, only: [:new, :create, :index, :show, :destroy] do
    resource :favorites, only: [:create, :destroy] 
end

resourceとなっている点

単数形にすると、/:idがURLに含まれなくなる。

コメント機能では「1人のユーザが1つの投稿に対して何度でもコメントできる」という仕様だったため、destroyをする際にidを受け渡して「どのコメントを削除するのか」を指定する必要があった。

いいね機能の場合は「1人のユーザーは1つの投稿に対して1回しかいいねできない」という仕様であるため、destroyをする際にもユーザーidと投稿(post_image)idが分かれば、どのいいねを削除すればいいのかが特定できる。
そのため、URLに/:idを含めない形にしている!!

resourceは「それ自身のidが分からなくても、関連する他のモデルのidから特定できる」といった場合に用いることが多い

実際にURLを確認

rails routes

favorites関連のルーティングが作成された!

post_image_favorites DELETE /post_images/:post_image_id/favorites(.:format)                                          favorites#destroy
                     POST   /post_images/:post_image_id/favorites(.:format)                                          favorites#create

Controller

いいね機能のコントローラを作成

いいね機能では他のモデルにあるような詳細ページや一覧ページなどのViewが必要ないため
今回はアクションを指定せずにコントローラを作成。

rails g controller favorites

いいね機能も、indexアクションやnewアクションは作成しない。

app/controllers/favorites_controller.rb

def create
  end

  def destroy
  end
end

createアクションとdestroyアクションの中身を実装

app/controllers/favortes_controller.rb

def create
    post_image = PostImage.find(params[:post_image_id])
    favorite = current_user.favorites.new(post_image_id: post_image.id)
    favorite.save
    redirect_to post_image_path(post_image)
  end

def destroy
    post_image = PostImage.find(params[:post_image_id])
    favorite = current_user.favorites.find_by(post_image_id: post_image.id)
    favorite.destroy
    redirect_to post_image_path(post_image)
end

View

app/views/post_images/show.html.erb

<% if @post_image.favorited_by?(current_user) %>
    <p>
      <%= link_to post_image_favorites_path(@post_image), method: :delete do %>
        ♥<%= @post_image.favorites.count %> いいね
      <% end %>
    </p>
    <% else %>
    <p>
      <%= link_to post_image_favorites_path(@post_image), method: :post do %>
        ♡<%= @post_image.favorites.count %> いいね
      <% end %>
    </p>
  <% end %>

投稿画像に付けられた「いいね」に、自分(ログインしているユーザ)が含まれているかをfavorited_by?メソッドで判定している。
「含まれるとき/含まれないとき」で、表示と機能を分け、リンクのaタグのメソッドを、条件によって変えている。

確認

実際に「いいね」を押して確かめる!


応用編

いいねのハートに色をつける方法

View

<% if book.favorited_by?(current_user) %>
  <%= link_to book_favorites_path(book), method: :delete do %>
    <i class="fas fa-heart" aria-hidden="true" style="color: red;"></i>
    <%= book.favorites.count %> いいね
  <% end %>
<% else %>
  <%= link_to book_favorites_path(book), method: :post do %>
    <i class="fas fa-heart" aria-hidden="true"></i>
    <%= book.favorites.count %> いいね
  <% end %>
<% end %>

ちなみにこれも学んだ!

前のページにリダイレクトする方法

redirect_to request.referer

ユーザーが直前にアクセスしたページにリダイレクトするために使用される!!
柔軟性の高いページ遷移を実現することができる🙆🏻‍♀️


いいね機能の復習!!
今日はここまで!

Discussion