LoginSignup
1
1

More than 1 year has passed since last update.

【Rails】ツイートを作成順ではなく、いいねした順に表示したい

Posted at

概要

ツイート投稿機能とツイートへのいいね機能を持つアプリケーションを開発中、
いいねした順番にツイートを取得する方法について調べたのでメモ。

環境

ruby 3.0.2
rails 6.1.4
mysql 8.0.26

やりたいこと

ツイートの作成順がデフォルトの時に、
ツイートの作成順ではなくユーザーがいいねした順にツイートを取得したい。

先に結論

reorderを使用し、中間テーブルのカラムを直接指定する

users_controller.rb
# ユーザー詳細画面で表示したい場合
  def show
    @user = User.find(params[:id])
    @favorites = @user.favorite_tweets.reorder('favorites.created_at DESC')
  end

以下、詳細

関連するモデル

user.rb
class User < ApplicationRecord
  has_many :tweets, dependent: :destroy
  has_many :favorites, dependent: :destroy
  has_many :favorite_tweets, through: :favorites, source: :tweet
end
tweet.rb
class Tweet < ApplicationRecord
  belongs_to :user
  has_many :favorites, dependent: :destroy
  has_many :favorite_tweets, through: :favorites, source: :tweet
# ツイートのデフォルトとしては投稿順に並べたいためここで指定
  default_scope -> { order(created_at: :desc) }
end
favorite.rb
class Favorite < ApplicationRecord
  belongs_to :user
  belongs_to :tweet
end

ER図

image.png

結論に至るまで

コンソールで確認しつつ試行錯誤。

# userに一人目のユーザーを取得
user = User.find(1)
# favoritesに、userがいいねしたツイートを取得
favorites = user.favorite_tweets

これだと、tweetのデフォルトである、
tweetsテーブルのcreated_atカラムの降順
での取得となってしまう。
(このデフォルトはtweet.rbのdefault_scopeで指定しているもの)

そもそもどんなクエリが発行されているのか?

ActiveRecordで発行されるSQLを確認するのに、to_sqlという便利なメソッドがあるとのこと。
先ほどの中身を確認。

# userに一人目のユーザーを取得
user = User.find(1)
# userがいいねしたツイートを取得するSQLを確認
user.favorite_tweets.to_sql
# 見やすいよう改行
=> 
"SELECT `tweets`.* 
FROM `tweets` 
INNER JOIN `favorites` 
ON `tweets`.`id` = `favorites`.`tweet_id` 
WHERE `favorites`.`user_id` = 1 
ORDER BY `tweets`.`created_at` DESC"

ORDER BY tweets.created_at DESC"

とあるように、tweetsテーブルのcreated_atカラムをDESCで並べている。

指定したいのは
ユーザーがツイートをいいねした順番
つまり、
中間テーブルのcreated_at
なので、

上記ORDER BYの箇所を

ORDER BY favorites.created_at DESC

にできればいいのでは?

defaultを上書きしたい
# userに一人目のユーザーを取得
user = User.find(1)
# userがいいねしたツイートを取得するSQLを確認
>> user.favorite_tweets.order('favorites.created_at DESC').to_sql
# 見やすいよう改行
=> 
"SELECT `tweets`.* 
FROM `tweets` 
INNER JOIN `favorites` 
ON `tweets`.`id` = `favorites`.`tweet_id` 
WHERE `favorites`.`user_id` = 1 
ORDER BY `tweets`.`created_at` DESC, favorites.created_at DESC"

ORDER BY tweets.created_at DESC, favorites.created_at DESC"

.orderでは、デフォルトの後の指定として追加できるだけのよう。

ここで結論

reorderで初期化の上、順番を指定

# userに一人目のユーザーを取得
user = User.find(1)
# userがいいねしたツイートを取得するSQLを確認
>> user.favorite_tweets.reorder('favorites.created_at DESC').to_sql
# 見やすいよう改行
=> 
"SELECT `tweets`.* 
FROM `tweets` 
INNER JOIN `favorites` 
ON `tweets`.`id` = `favorites`.`tweet_id` 
WHERE `favorites`.`user_id` = 1 
ORDER BY tweet_bookmarks.created_at DESC"

無事、意図通りのいいね順で取得することができた。

参考にした記事

  • reorder含む、default_scopeの初期化

  • 【Railsドキュメント】reorderについて

最後に

より良い方法や間違い等ありましたらご指摘いただけますと幸いです!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1