У меня есть приложение, которое хранит рейтинги игроков для каждого турнира.Поэтому у меня есть ассоциация «многие ко многим»:
Tournament
has_many :participations, :order => 'rating desc'
has_many :players, :through => :participations
Participation
belongs_to :tournament
belongs_to :player
Player
has_many :participations
has_many :tournaments, :through => :participations
Модель участия имеет поле rating
(с плавающей точкой), в котором хранится значение рейтинга (это как очки очков) для каждого игрока в каждом турнире.
То, что я хочу - получить последние 10 рангов игрока (rank
- это позиция игрока в конкретном турнире, основанная на его рейтинге: чем больше рейтинг, тем выше рейтинг).Сейчас, чтобы получить рейтинг игрока в турнире, я загружаю все участия в этом турнире, сортирую их по полю rating
и получаю индекс участия игрока с кодом рубина:
class Participation < ActiveRecord::Base
belongs_to :player
belongs_to :tournament
def rank
tournament.participations.index(self)
end
end
Метод rank
Участник получает родительский турнир, загружает все участия в турнире (по заказу rating desc
) и получает собственный индекс внутри этой коллекции
, а затем что-то вроде:
player.participations.last.rank
Одна вещь, которую яне нравится - он должен загрузить все участия в турнире, и в случае, если мне нужны рейтинги игроков для последних 10 турниров, он загружает более 5.000 предметов (и его количество будет расти с добавлением новых игроков).
Я считаю, что должен быть способ использовать SQL для него.На самом деле я пытался использовать переменные SQL:
find_by_sql("select @row:=@row+1 `rank`, p.* from participations p, (SELECT @row:=0) r where(p.tournament_id = #{tournament_id}) order by rating desc limit 10;")
Этот запрос выбирает топ-10 рейтингов данного турнира.Я пытался изменить его, чтобы выбрать последние 10 участников для данного пользователя и его звания.
Буду признателен за любую помощь.(Я думаю, что решением будет SQL-запрос, поскольку он довольно сложен для ActiveRecord).
PS Я использую rails3.0.0.beta4
UPD:
Вот окончательный SQL-запрос, который получает последние 10 рангов игрока (кроме того, он также загружает и участвующие турниры)
SELECT *, (
SELECT COUNT(*) FROM participations AS p2
WHERE p2.tour_id = p1.tour_id AND p2.rating > p1.rating
) AS rank
FROM participations AS p1 LEFT JOIN tours ON tours.id = p1.tour_id WHERE p1.player_id = 68 ORDER BY tours.date desc LIMIT 10;