Song
という名前のモデルがあります。 Listen
という名前のモデルもあります。 Listen
belongs_to :song
、および歌:has_many listens
(何度も聴くことができます)。
私のモデルでは、self.top
メソッドを定義します。このメソッドは、最も多く聴かれた上位5曲を返します。 has_many
関係を使用してそれを達成するにはどうすればよいですか?
私はRails 3.1。
ありがとう!
名前付きスコープ の使用:
class Song
has_many :listens
scope :top5,
select("songs.id, OTHER_ATTRS_YOU_NEED, count(listens.id) AS listens_count").
joins(:listens).
group("songs.id").
order("listens_count DESC").
limit(5)
Song.top5 # top 5 most listened songs
さらに良いことに、counter_cache
クエリで1つのテーブルを使用するだけなので、高速になります
歌のクラスは次のとおりです。
class Song < ActiveRecord::Base
has_many :listens
def self.top
order('listens_count DESC').limit(5)
end
end
次に、リスニングクラス:
class Listen < ActiveRecord::Base
belongs_to :song, counter_cache: true
end
必ず移行を追加してください。
add_column :comments, :likes_count, :integer, default: 0
ボーナスポイント、テストの追加:
describe '.top' do
it 'shows most listened songs first' do
song_one = create(:song)
song_three = create(:song, listens_count: 3)
song_two = create(:song, listens_count: 2)
popular_songs = Song.top
expect(popular_songs).to eq [song_three, song_two, song_one]
end
end
または、上記のメソッドを使用する場合は、ここでもう少し簡単になり、scope
ではなくクラスメソッドを使用します
def self.top
select('comments.*, COUNT(listens.id) AS listens_count').
joins(:listens).
group('comments.id').
order('listens_count DESC').
limit(5)
end
Rails 4.xの場合、関連付けのない行が重要な場合は、これを試してください。
scope :order_by_my_association, lambda {
select('comments.*, COUNT(listens.id) AS listens_total')
.joins("LEFT OUTER JOIN listens ON listens.comment_id = comments.id")
.group('comments.id')
.order("listens_total DESC")
}