🫶

【Rails】 いいね機能

2023/07/10に公開

🍍今回の流れ

完成図

https://www.loom.com/share/b332fc8c8d2041e8b26cda8037b6cf6a?sid=0a83d696-e6a2-4b7b-bcc3-175349f85a13

モデル

  • favoriteモデルを追加
  • ユーザー1人につき1つの投稿に1いいねしかできないようにする
     (twitterやinstagramと同じ仕様にする)

コントローラ

  • favoritesコントローラーを追加
    createアクションを追加
    destroyアクションを追加
  • いいね♥を作成・削除した後は、行う前にいた画面に遷移すること。

ビュー

  • 投稿一覧画面にいいね♥ボタン、いいね数を表示する
  • 投稿詳細画面にいいね♥ボタン、いいね数を表示する
  • いいねしていない投稿→いいね作成ボタンを表示
  • いいねしている投稿→いいね削除ボタンを表示

🍍作成

モデル

favoriteモデルを追加

rails g model favorite

favoriteテーブルの作成
マイグレーションファイルの中身を編集

db/migrate/〇〇〇_create_favorites_rb
class CreateFavorites < ActiveRecord::Migration[6.1]
  def change
    create_table :favorites do |t|
      t.integer :user_id
      t.integer :book_id
      t.timestamps
    end
  end
end
カラム名 データ型 カラムの説明
id integer 「いいね」ごとのID
user_id integer 「いいね」したユーザのID
book_id integer 「いいね」された投稿のID

アソシエーションを設定
アソシエーション=モデル同士のつながり

コメントなし
ravorite.rb
class Favorite < ApplicationRecord
  belongs_to :user
 belongs_to :book
end
favorite.rb
class Favorite < ApplicationRecord
  belongs_to :user
  # Favoriteはuserに属している
 belongs_to :book
 # Favoriteはbookに属している
end

💎belongs_to→属しているとはどういう関係の事を言うのか?
つまり、1:Nの関係を表している!!

コメントなし
user.rb
has_many :favorites, dependent: :destroy
user.rb
()
has_many :favorites, dependent: :destroy

# ユーザーにたくさんのいいねを持つことができるようにする
# いいねはユーザーに依存してるから、ユーザーが消えたらいいねも消えるようにする
()

全体のイメージ

上記の図だと、ユーザー1が投稿2に、ユーザー2が投稿2と3にいいねを押していることになる。

コメントなし
book.rb
has_many :favorites, dependent: :destroy

def favorited_by?(user)
    favorites.exists?(user_id: user.id)
end
book.rb
has_many :favorites, dependent: :destroy
#いいねはbookに依存してるからbookが消えたらいいねも消えるようにする
def favorited_by?(user)
#現在ログインしているユーザーによっていいねされてる?
    favorites.exists?(user_id: user.id)
#いいねは存在してる?(いいねを既に押してるか、押していないか)
end

favorited_by?メソッド

このメソッドを用いることで引数で渡されたユーザーidがfavoritesテーブルに存在(exists)してるか?どうかを確認できる。

  • 引数で渡されたuserがいいねしていれば→true
  • 引数で渡されたuserがいいねしていなければ→false
    が返される。

コントローラ

favoritesコントローラーを追加

$ rails g controller Favorites

createアクション、destroyアクションを追加

コメントなし
facorites_controller.rb
class FavoritesController < ApplicationController
 def create
    book = Book.find(params[:book_id])
    favorite = current_user.favorites.new(book_id: book.id)
    favorite.save
    redirect_to books_path
    
  end
  
  def destroy
    book = Book.find(params[:book_id])
    favorite = current_user.favorites.find_by(book_id: book.id)
    favorite.destroy
    redirect_to books_path
  end

💎book_id: book.idじゃなくで、book_idだけじゃダメなのなんで?
 book_idだけわかればbook.idなくてももうどのいいねかわかるくない?

もしかしてcurrent_userだからbook.idで自分のidでいいねしてるbook_idを探してるの??

ルーティング

routes.rb
resources :books, only: [:index, :show, :edit, :create, :update, :destroy] do
     resource :favorites, only: [:create, :destroy]
  end

ルーティングをネストさせる。
ネストとは、あるコントローラーへのルーティングの記述の中に別のコントローラへのルーティングを記述すること。

resourceとresourcesの違い

今回はresourceで(s)をなくすことでURLに/:idが含まれなくなる。→いいね♥機能の場合、1人のユーザーが1つのbookにいいね♥できるのが1回のみなので、URLにparams[:id]を使わなくてもいいためresourceになっている。

💎resourceは主にどういうときに使う?

いいね機能の場合、1人のユーザーは1つの投稿に対して1回しかいいねできないという制約があります。そのため、いいねの削除を行う際には、ユーザーIDと投稿IDがわかれば、どのいいねを削除するかを特定できます。したがって、いいねのIDをURLに含める必要はない!

ビュー

  • 投稿一覧画面にいいね♥ボタン、いいね数を表示する
  • 投稿詳細画面にいいね♥ボタン、いいね数を表示する
  • いいねしていない投稿→いいね作成ボタンを表示
  • いいねしている投稿→いいね削除ボタンを表示
コメントなし
_favorite.html.erb
 <% 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>
                <span style="color: red;"><%= book.favorites.count%>
             <% end %>
         <% else %>
             <%= link_to book_favorites_path(book), method: :post do %><%= book.favorites.count %>
             <% end %>
 <% end %>
_favorite.html.erb
#ログインしてるユーザーがいいねしたら?(↓の説明)
 <% if book.favorited_by?(current_user) %>
   <%= link_to book_favorites_path(book), method: :delete do %>
 #いいねされた後もう一度押したらいいねが削除されるようにしたいのでmethodはdelete
      <i class="fas fa-heart" aria-hidden="true" style="color: red;"></i>
 #赤い♥のアイコンが表示される
      <span style="color: red;"><%= book.favorites.count%>
 #赤い文字でいいねの数を表示
   <% end %>
 #いいねを削除したら?(↓の説明)
 <% else %>
     <%= link_to book_favorites_path(book), method: :post do %>
 #いいねを削除したら次はいいねがcreateされてほしいのでmethodはpost<%= book.favorites.count %>
      <% end %>
 <% end %>

今回は投稿一覧と詳細画面に入れたいので

<th><%= render'favorites/favorite' %></th>

上記のように入れたい場所にrenderして入れる。

🍍おわり

お疲れさまでした🌱

Discussion