2009-08-14 6 views
2

J'ai 3 tables - sites, utilisateurs, et mises à jour (qui ont un nombre entier pour l'évaluation) - et je veux écrire une requête qui renverra une liste de tous mes lieux ainsi que leurs estimations moyennes en utilisant seulement la mise à jour la plus récente pour chaque personne, paire de sites. Par exemple, si l'utilisateur 1 évalue le lieu A une fois à 9 heures avec un 4, puis le réévalue à 17 heures avec un 3, je veux seulement utiliser la note 3, car c'est plus récent. Il existe également des conditions facultatives, telles que la date à laquelle les mises à jour doivent être récentes et s'il existe un tableau d'ID utilisateur dans lequel les utilisateurs doivent se trouver.Complexe Rejoindre des requêtes dans Rails

Quelqu'un a-t-il une suggestion sur la meilleure façon d'écrire quelque chose comme ça pour qu'il soit propre et efficace? Je l'ai écrit la named_scope suivante qui devrait faire l'affaire, mais il est assez laid:

named_scope :with_avg_ratings, lambda { |*params| 
hash = params.first || {} 
has_params = hash[:user_ids] || hash[:time_ago] 
dir = hash[:dir] || 'DESC' 
{ 
    :joins => %Q{ 
    LEFT JOIN (select user_id, venue_id, max(updated_at) as last_updated_at from updates 
    WHERE type = 'Review' GROUP BY user_id, venue_id) lu ON lu.venue_id = venues.id 
    LEFT JOIN updates ON lu.last_updated_at = updates.updated_at 
    AND updates.venue_id = venues.id AND updates.user_id = lu.user_id 
    }, 
    :select => "venues.*, ifnull(avg(rating),0) as avg_rating", 
    :group => "venues.id", 
    :order => "avg_rating #{dir}", 
    :conditions => Condition.block { |c| 
    c.or { |a| 
     a.and "updates.user_id", hash[:user_ids] if hash[:user_ids] 
     a.and "updates.updated_at", '>', hash[:time_ago] if hash[:time_ago] 
    } if has_params 
    c.or "updates.id", 'is', nil if has_params 
    } 

} 

}

I comprennent le dernier « updates.id est nulle » condition parce que je veux toujours les lieux retournés même s'ils n'ont aucune mise à jour associée à eux.

Merci, Eric

Répondre

1

Aïe, qui ressemble à un emploi pour find_by_sql pour moi. Lorsque vous faites quelque chose d'aussi complexe, je trouve qu'il est préférable de retirer le travail d'ActiveRecord et de DIY.