QA@IT

お気に入りされた数が多い投稿を降順で取得する

2665 PV

Railsで UserPostを作成でき、各ユーザーは好きなポストにひとつ「お気に入り」をすることができるようにしています。

具体的には以下のようなコードを使っています。

class Post < ActiveRecord::Base
  has_many :favs, dependent: :destroy
  has_many :faved_users, through: :favs, source: :user
end

class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
  has_many :favs, dependent: :destroy
  has_many :faved_posts, through: :favs, source: :post
end

class Fav < ActiveRecord::Base
  belongs_to :user
  belongs_to :post
end

そして最もお気に入りを多くされてるPostを表示するために
Word.order(faved_users: :asc).limit 3 とすると faved_users がカラムとして存在しないためにエラーになります。

中間テーブルを使っている場合はエラーになることがわかったので、
Postfavs_countというカラムを追加し、
お気に入りが登録や削除された時に数字を書き換えるように処理をすることにしたのですが
どうしてもやや煩雑になってしまいます。

中間テーブルを介して取得するSQLを書いたらできるとは思うのですが、
書き方がわからない上にどの程度遅くなるのかもわかりません。

このような状態ではどのようなアプローチが一般的に取られるのでしょうか?
また、SQLにて解決するのが一般的であればどのように書くかも教えて頂けると非常に助かります。

回答

間違ってたらすいません。

おそらくこんな感じになるのではないでしょうか?

top_post_id = Fav.group(:post_id).order("count_all desc").count.first.first
Post.find(top_post_id)

これで一番お気に入りされているポストが求められると思います。

一行目は何をしているかというと、
まずFav内をpost_id毎に縛ります。
その後、それぞれが何個縛られたかを求めます。
そしてその個数を、降順に並べて、一番最初のpost_idを取ってくるという感じです。

二行になってしまいましたが、うまい方法があれば一行になるかもしれません。

あと気になったんですが、

has_many :favs

と書いてますが、Userは1つだけしかfavできないのであれば、

has_one :fav

の方がいいんじゃないでしょうか?

編集 履歴 (0)
  • こんなふうに書けるんですね、勉強になります。`Post.find(Fav.group(:post_id).order("count_all desc").count.keys[0..9]).reverse` で人気順で10件取得することが出来ました。(何故reverseが必要なのかはよくわかってないのですが…。) -
  • `fav`は各ユーザーがそれぞれの`Post`に対し一つだけなのですが、全体としては複数を持つので `has_many`を使っています。初めの書き方だとどちらか曖昧でしたね。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。