🍎

【Rails】いいね機能実装(同期)

2023/07/25に公開
  • アプリケーション作成済
  • 「Userモデル」「Bookモデル」「Favoriteモデル」を使用して実装
  • 完成イメージ ↓
    altテキスト

1.Favoriteモデル、favoritesテーブルを作成

いいね機能用にFavoriteモデルとfavoritesテーブルを作成

ターミナル
$ rails g model Favorite user_id:integer book_id:integer

実行結果として下記が表示されればOK!

ターミナル
Running via Spring preloader in process 14418
      invoke  active_record
      create    db/migrate/20230724124903_create_favorites.rb
      create    app/models/favorite.rb
      invoke    test_unit
      create      test/models/favorite_test.rb
      create      test/fixtures/favorites.yml
ターミナル
$ rails db:migrate
  • ここまでで「Favoriteモデル」「favoritesテーブル」が生成された
  • 「user_id:integer」「book_id:integer」=カラムを外部キーとして生成

2.アソシエーションを設定

  • 1人のUserはいいねをたくさん持っている(複数の投稿にいいねをすることができる)
  • 1つのbookはたくさんのUserからのいいねを持っている

・・・つまり、UserとBookは「 多:多 」の関係性であるため、「 1:N 」の関係性を作れるように「中間テーブル」を作成する必要がある。

中間テーブルとして「favoritesテーブル」を作成し、「user_id」と「book_id」を結びつける。

app/models/user.rb
class User < ApplicationRecord
:
:
  has_many :books, dependent: :destroy
  has_many :favorites, dependent: :destroy  ←これを追記!
:
  • 「dependent: :destroy」=対象のUserが削除されたら、関連するFavoriteも削除される
app/models/book.rb
class Book < ApplicationRecord
:
  belongs_to :user
  has_many :favorites, dependent: :destroy  ←これを追記!
  • 「dependent: :destroy」=対象のBookが削除されたら、関連するFavoriteも削除される
app/models/favorite.rb
class Favorite < ApplicationRecord
  belongs_to :user
  belongs_to :book
end

3.Bookモデルにメソッドを定義

app/models/book.rb
:
:
  def favorited_by?(user)
    favorites.exists?(user_id: user.id)
  end
  • favorited_by?メソッド=favoritesテーブルにuser_idが存在するか(exists?)を調べる
     - 存在すればtrue、存在しなければfalseを返す

4.ルーティング設定

app/config/routes.rb
Rails.application.routes.draw do
:
:
 resources :books, only: [:new, :create, :index, :show, :edit, :update, :destroy] do
   resource :favorites, only: [:create, :destroy]
 end
:
  • Userがいいねしたのは、どの「本」なのか。がわかるように、booksコントローラーのルーティングにネストさせる
  • createアクション(いいねをつける)、destroyアクション(いいねを削除)を記述

$ rails routesの結果

ターミナル
book_favorites DELETE /books/:book_id/favorites(.:format)   favorites#destroy
               POST   /books/:book_id/favorites(.:format)   favorites#create
  • ルーティングに「:book_id」が含まれている!

resource(単数形)resources(複数形)の違いについて、まだよく理解できていないので勉強します…

5.コントローラー作成

いいね機能用にfavoritesコントローラーを作成

ターミナル
$ rails g controller favorites

ルーティングで設定したcreate、destroyアクションを記述

app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController
  def create
  end
  
  def destroy
  end
end

6.アクションを実装

app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController
  def create
    book = Book.find(params[:book_id])   #外部キーである「book_id」を取得
    favorite = current_user.favorites.new(book_id: book.id) #ログインしているユーザーがいいねをした本のidを取得し、いいねをつける
    favorite.save  #いいねを保存
    redirect_to request.referer  #アクション実行後に同ページに遷移(ページは変わらない)
  end

  def destroy
    book = Book.find(params[:book_id])   #外部キーである「book_id」を取得
    favorite = current_user.favorites.find_by(book_id: book.id)  #ログインしているユーザーがいいねをした本のidを取得
    favorite.destroy  #いいねを削除
    redirect_to request.referer  #アクション実行後に同ページに遷移(ページは変わらない)
  end
end

7.ビューを作成

books/showページに実装

app/views/books/show.html.erb
  <% if @book.favorited_by?(current_user) %>
    <%= link_to book_favorites_path(@book), method: :delete do %>
      ♥<%= @book.favorites.count %>
    <% end %>
  <% else %>
    <%= link_to book_favorites_path(@book), method: :post do %>
      ♡<%= @book.favorites.count %>
    <% end %>
  <% end %>
  • Bookモデルに記述したfavorited_by?メソッドに引数としてcurrent_userを渡す
  • current_user(ログインしているユーザー=自分)が含まれている場合、destroyアクションが動く
  • current_user(ログインしているユーザー=自分)が含まれていない場合、createアクションが動く

ここまでで、いいねが表示されるようになりました!

altテキスト


こちらの記事を参考にさせていただきました🙏

https://qiita.com/SAPPOROBEER/items/13f7a3bedd9690b90a5b

https://qiita.com/RIN_HM/items/968abd9e31df6631a3ed

Discussion