2010-03-20 7 views
1

J'ai trois modèles: Utilisateur, RaceWeek, Race.Rails Association Question

associations actuelles:

class User < ActiveRecord::Base 
    has_many :race_weeks 
end 

class RaceWeek < ActiveRecord::Base 
    belongs_to :user 
    has_many :races 
end 

class Race < ActiveRecord::Base 
    belongs_to :race_week 
end 

Ainsi, le user_id est une clé étrangère dans Raceweek et race_week_id est une clé étrangère dans la course.

fastest_time est un attribut du modèle Race.

QUESTION: Quelle est la meilleure façon de récupérer une liste d'utilisateurs ayant les meilleurs temps de course X?

+0

S'il vous plaît ranger cette question en le formatant correctement. –

Répondre

1

Vous pouvez le faire comme ceci:

users = User.all(:limit => X, :joins => {:race_weeks => :races}, :order => "reces.fastest_time DESC").uniq 

Si vous avez spécifié correctement association has_many :through, alors vous pouvez même le faire comme ceci:

users = User.all(:limit => X, :joins => :races, :order => "reces.fastest_time DESC").uniq 

Dans cette solution, vous obtenez ce que vous vouloir avec une requête, mais deux jointures. Et cette méthode uniq n'est pas très bonne, sauf si vous utiliseriez petit X.

+0

Comment aurais-je besoin de modifier cela si je voulais inclure les champs Race dans l'objet Utilisateur retourné afin que je puisse accéder à la plus rapide? – keruilin

+0

Je pense que vous devez avoir des associations correctes dans les courses de modèles et d'étendues avec ': order => 'highest_time DESC''. Mais il va faire des requêtes SQL supplémentaires. Ensuite, vous pouvez l'obtenir comme ceci: 'users.each {| a | met un.races.fastest.first.fastest_time' – klew

1

Quelque chose comme:

races = Race.all(:order => "fastest_time desc", :limit => X, :include => {:race_week => :user}) 
users = races.map{|race| race.race_week.user}.uniq 

Note: n'a pas testé cela.

+0

Pourriez-vous expliquer comment cela: include works? Je ne suis pas tout à fait sûr d'avoir ce que: course_week =>: l'utilisateur est en train de faire. – keruilin

+0

En outre, vous avez raison, je veux juste connaître la liste des utilisateurs avec les meilleurs temps X course (Joe pourrait avoir les 10 meilleurs temps). Cependant, les meilleurs utilisateurs de X avec les temps de course les plus rapides (Joe a le temps le plus rapide, mais ensuite les 9 prochains utilisateurs distincts). – keruilin

+0

inclure est fondamentalement juste une optimisation de base de données. Il indique à ActiveRecord d'aller de l'avant et d'aller chercher toutes les courses et semaines de course associées à la fois. Si vous avez omis le: include, cela fonctionnerait encore, il suffit d'effectuer beaucoup plus de requêtes. – jrallison

1

Compte tenu de votre modèle actuel, les éléments suivants devraient fonctionner.

race_weeks = RaceWeek.find_by_sql(["SELECT user_id FROM race_weeks JOIN races ON races.race_week_id = race_weeks.id ORDER BY races.fastest_time desc LIMIT ?", X) 
users = User.find(race_weeks.collect(&:user_id).uniq) 

Je sais qu'il a besoin de deux apparence ups mais la deuxième recherche devrait être très rapide puisque vous cherchez seulement des enregistrements X par leur clé primaire.

+0

Cela retournerait les meilleurs utilisateurs de X avec les temps de course les plus rapides, pas nécessairement la liste des utilisateurs avec les meilleurs temps X course. – jrallison

+0

J'ai modifié mon code pour satisfaire cette exigence que je suppose avoir mal comprise. –

+0

Votre limite limite toujours le nombre d'utilisateurs retournés, non? Cela signifie que vous retournerez toujours les utilisateurs X. La façon dont la question est encadrée, vous voulez retourner X fois le plus rapide, quel que soit le nombre d'utilisateurs ont obtenu ces meilleurs temps. C'EST À DIRE. L'utilisateur A a les 10 temps de course les plus rapides. Si X = 10, vous ne devez renvoyer qu'un seul utilisateur. – jrallison

Questions connexes