У меня есть эта область действия в моей модели художника, которая дает мне художников в порядке их популярности в течение определенного периода времени. popularity
в таблице popularity_caches
вычисляется каждый день.
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")
}
Это похоже на работу, кроме случаев, когда я хочу получить счет: Artist.by_popularity.count
. В ответ я получаю хэш-фанк (вероятно, количество исполнителей, у которых есть популярность в течение этого периода):
#<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
Это SQL, который я, вероятно, хочу получить взамен:
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
Чтобы получить счетчик, мне пришлось создать отдельный метод, который в значительной степени делает то же самое, за исключением того, что SQL формируется по-разному. Это отстой, потому что, когда я хочу разбить на страницы, я должен пропустить две вещи:
@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 => ...
)
Это пахнет мной, потому что оно очень хрупкое.
Есть ли способ сделать это в ARel? Может быть, переопределить, как он считает вещи (отличный от artist.id) и удаляет group by
, чтобы он не возвращал хэш для счета?
Спасибо!