2014-08-27 52 views
0

好的,所以我有這個Concern其中包含一個方法top用於檢索記錄順序的次數由某人已經聆聽他們(如果該記錄是一首歌曲,直接或通過歌曲,如果它是別的東西,如流派或藝術家)。如果是平局,則按其他網站上的受歡迎程度排序記錄。如何將此SQL轉換爲ActiveRecord查詢?

以下代碼幾乎完美地工作。它以正確的順序返回一個對象數組。我的主要問題是我得到一個數組而不是一個關係。因此,來電者不能再添加諸如Song.top.limit 3Genre.top.offset(10).limit(5)之類的內容。

這裏是我的方法:

def top(options = {}) 
    tname = self.name.tableize 

    inner_select = self.select("#{tname}.*,COUNT(DISTINCT(listens.id)) AS listens_count") 
    inner_select = inner_select.joins(:songs) unless self.name == 'Song' 
    inner_select = inner_select.joins("LEFT JOIN listens ON listens.song_id = songs.id") 
    inner_select = inner_select.where("listens.user_id = ?", options[:for].id) if options[:for].is_a? User 
    inner_select = inner_select.group("#{tname}.id").to_sql 

    # this is the part that needs fixin' 
    find_by_sql(" 
     SELECT 
      #{tname}.*, 
      #{tname}.listens_count, 
      SUM(sources.popularity) AS popularity_count 
     FROM (#{inner_select}) AS #{tname} 
     LEFT JOIN sources ON 
      sources.resource_id = #{tname}.id 
      AND 
      sources.resource_type = '#{self.name} 
     GROUP BY #{tname}.id 
     ORDER BY listens_count DESC, popularity_count DESC 
    ") 
end 

下面是生成,按要求SQL查詢。這是Song.top

SELECT 
    songs.*, 
    songs.listens_count, 
    SUM(sources.popularity) AS popularity_count 
FROM (SELECT songs.*,COUNT(DISTINCT(listens.id)) AS listens_count FROM "songs" LEFT JOIN listens ON listens.song_id = songs.id GROUP BY songs.id) AS songs 
LEFT JOIN sources ON 
    sources.resource_id = songs.id 
    AND 
    sources.resource_type = 'Song' 
GROUP BY songs.id 
ORDER BY listens_count DESC, popularity_count DESC 

這是Artist.top

SELECT 
    artists.*, 
    artists.listens_count, 
    SUM(sources.popularity) AS popularity_count 
FROM (SELECT artists.*,COUNT(DISTINCT(listens.id)) AS listens_count FROM "artists" INNER JOIN "artists_songs" ON "artists_songs"."artist_id" = "artists"."id" INNER JOIN "songs" ON "songs"."id" = "artists_songs"."song_id" LEFT JOIN listens ON listens.song_id = songs.id GROUP BY artists.id) AS artists 
LEFT JOIN sources ON 
    sources.resource_id = artists.id 
    AND 
    sources.resource_type = 'Artist' 
GROUP BY artists.id 
ORDER BY listens_count DESC, popularity_count DESC 
+0

它可能是有點容易(從日誌,或使用'to_sql') – IS04 2014-08-27 20:28:08

回答

0

所以,我找到了答案,原來我已經徹底無緣from方法。我會在這裏發表最後的方法,以防萬一別人是我瞎:如果添加生成的`sql`發佈

def top(options = {}) 
    tname = self.name.tableize 

    inner_select = self.select("#{tname}.*,COUNT(DISTINCT(listens.id)) AS listens_count"). 
     joins("LEFT JOIN listens ON listens.song_id = songs.id"). 
     group("#{tname}.id") 

    inner_select = inner_select.joins(:songs) unless self.name == 'Song' 
    inner_select = inner_select.where("listens.user_id = ?", options[:for].id) if options[:for].is_a? User 

    inner_select = "(#{inner_select.to_sql}) as #{tname}" 

    select("#{tname}.*,#{tname}.listens_count,SUM(sources.popularity) AS popularity_count"). 
     from(inner_select). 
     joins("LEFT JOIN sources ON sources.resource_id = #{tname}.id AND sources.resource_type = '#{self.name}'"). 
     group("#{tname}.id"). 
     order("listens_count DESC, popularity_count DESC") 
end