【Rails】 いいね機能
🍍今回の流れ
完成図
モデル
- favoriteモデルを追加
- ユーザー1人につき1つの投稿に1いいねしかできないようにする
(twitterやinstagramと同じ仕様にする)
コントローラ
- favoritesコントローラーを追加
createアクションを追加
destroyアクションを追加 - いいね♥を作成・削除した後は、行う前にいた画面に遷移すること。
ビュー
- 投稿一覧画面にいいね♥ボタン、いいね数を表示する
- 投稿詳細画面にいいね♥ボタン、いいね数を表示する
- いいねしていない投稿→いいね作成ボタンを表示
- いいねしている投稿→いいね削除ボタンを表示
🍍作成
モデル
favoriteモデルを追加
rails g model favorite
favoriteテーブルの作成
マイグレーションファイルの中身を編集
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 |
アソシエーションを設定
アソシエーション=モデル同士のつながり
コメントなし
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :book
end
class Favorite < ApplicationRecord
belongs_to :user
# Favoriteはuserに属している
belongs_to :book
# Favoriteはbookに属している
end
💎belongs_to→属しているとはどういう関係の事を言うのか?
つまり、1:Nの関係を表している!!
コメントなし
has_many :favorites, dependent: :destroy
(略)
has_many :favorites, dependent: :destroy
# ユーザーにたくさんのいいねを持つことができるようにする
# いいねはユーザーに依存してるから、ユーザーが消えたらいいねも消えるようにする
(略)
全体のイメージ
上記の図だと、ユーザー1が投稿2に、ユーザー2が投稿2と3にいいねを押していることになる。
コメントなし
has_many :favorites, dependent: :destroy
def favorited_by?(user)
favorites.exists?(user_id: user.id)
end
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アクションを追加
コメントなし
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を探してるの??
ルーティング
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に含める必要はない!
ビュー
- 投稿一覧画面にいいね♥ボタン、いいね数を表示する
- 投稿詳細画面にいいね♥ボタン、いいね数を表示する
- いいねしていない投稿→いいね作成ボタンを表示
- いいねしている投稿→いいね削除ボタンを表示
コメントなし
<% 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 %>
#ログインしてるユーザーがいいねしたら?(↓の説明)
<% 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