开发者

Possible override the way count works, or finding a better way, altogether to do this

开发者 https://www.devze.com 2023-04-10 13:33 出处:网络
I have this scope in my artist model that gives me the artists, in the order of their popularity within a certain time period. popularity in the popularity_caches table is computed every day.

I have this scope in my artist model that gives me the artists, in the order of their popularity within a certain time period. popularity in the popularity_caches table is computed every day.

scope :by_popularity, lambda { |*args|
  options = (default_popularity_options).merge(args[0] || {})

  select("SUM(popularity) AS popularity, artists.*").
from("popularity_caches FORCE INDEX (popularity_cache_group), artists FORCE INDEX (index_artists_on_id_and_genre_id)").
where("popularity_caches.target_type = 'Artist'").
where("popularity_caches.target_id = artists.id").
where("popularity_caches.time_frame = ?", options[:time_frame]).
where("popularity_caches.started_on > ?", options[:started_on]).
where("popularity_caches.started_on < ?", options[:ended_on]).
group("artists.id").
order("popularity DESC")
}

This seems to work except when I want to get the count: Artist.by_popularity.count. I get a funky hash in return (probably the count of artists that have popularity_caches within that period):

#<OrderedHash {295954=>1, 20143=>1, 157532=>1, 181291=>1, 300086=>1, 50100=>1, 262898=>1, 293888=>1, 130158=>2, 279943=>1, 336758=>1, 100201=>1, 134290=>2, 22726=>3, 144620=>2, 62497=>2 # snip

This is the SQL I probably want in return:

SELECT COUNT(DISTINCT(artists.id)) AS count_all
FROM popularity_caches FORCE INDEX (popularity_cache_group), artists FORCE INDEX (index_artists_on_id_and_genre_id)
WHERE (popularity_caches.target_type = 'Artist')
  AND (popularity_caches.target_id = artists.id)
  AND (popularity_caches.time_frame = 'week')
  AND (popularity_caches.started_on > '2011-02-28 16:00:00')
  AND (popularity_caches.started_on < '2011-10-05')
ORDER BY popularity DESC

To get the count, I had t开发者_JS百科o make a separate method that pretty much does the same thing, except the SQL is formed differently. It kinds sucks through, because when I want to paginate, I have to pass two things:

@artists = Artists.by_popularity(some args).paginate(
  :total_entries => Artist.count_by_popularity(pass in the same args here as in Artist.by_popularity),
  :per_page => 5,
  page => ...
)

That smells to me because it's very brittle.

Is there a way to do this in ARel? Maybe override how it counts things (distinct artists.id) and removing the group by so it doesn't return a hash for the count?

Thanks!


Solved with the amazing scuttle.io:

PopularityCach.select(
  Arel::Nodes::Group.new(Artist.arel_table[:id]).count.as('count_all')
).where(
  PopularityCach.arel_table[:target_type].eq('Artist').and(
    PopularityCach.arel_table[:target_id].eq(Artist.arel_table[:id]).and(
      PopularityCach.arel_table[:time_frame].eq('week').and(
        PopularityCach.arel_table[:started_on].gt('2011-02-28 16:00:00').and(
          PopularityCach.arel_table[:started_on].lt('2011-10-05')
        )
      )
    )
  )
).order(:popularity).reverse_order
0

精彩评论

暂无评论...
验证码 换一张
取 消