2009-03-31 6 views
3

Disons que j'ai des modèles: Utilisateur et Objet et relation plusieurs-à-plusieurs entre eux. Comment obtenir des utilisateurs qui ont exactement (pas plus) d'éléments avec les attributs définis, c'est-à-dire les utilisateurs qui ont des éléments avec des couleurs = ['rouge', 'noir'].Inversé has_many dans Rails

Bien sûr, je peux faire quelque chose comme ceci:

User.all :joins => [:items, :items], :conditions => {:"items.color" => "red", :"items_users.color" => 'black'} 

Mais pour d'autres attributs, il va être assez lourd. Je peux le faire aussi:

User.all(:conditions => ["items.color in (?), ['red', 'black']], :include => :items) 

Mais celui-ci renvoie également aux utilisateurs avec des éléments ayant des couleurs = [ « rouge », « noir », « bleu », « etc »]

La seule solution est obtenir tout et trier avec la syntaxe ruby? Comment le faire dans une requête SQL ou une syntaxe Rails AR?

Répondre

1

La façon qui optimise le temps du programmeur et la lisibilité, à mon avis:

#get all users who have items which are both red and black but no other colors 
candidate_users = User.all(:include => :items) 
candidate_users.reject! do |candidate| 
    candidate.items.map {|item| item.color}.sort != ['black', 'red'] 
end 

Si vous attendez à une boucle à travers un camion plein métrique d'utilisateurs là-bas, vous aurez besoin de SQL vers le haut. Attention: SQL n'est pas mon sac, bébé: test avant utilisation.

select users.*, items.* FROM users 
    INNER JOIN items_users ON (items_users.user_id = users.id) 
    INNER JOIN items ON (items_users.item_id = items.id) 
    GROUP BY users.id HAVING COUNT(DISTINCT items.color) = 2 

Ce que je pense que désordre mal fait:

1) Grabs chaque combinaison utilisateur/article 2) vanner vers le bas pour les utilisateurs qui ont des éléments d'exactement deux couleurs distinctes

Ce qui signifie que vous » ll faut:

candidate_users.reject! do |candidate| 
    candidate.items.map {|item| item.color}.sort != ['black', 'red'] 
end 

Vous pouvez probablement éliminer la nécessité pour le rubis ici tout à fait, mais le SQL va obtenir sept saveurs de laid. (Croix joint, oh mon ...)

+0

Bien que simple, cela brise les conventions de rails, et empêche le chargement paresseux dans les chaînes (en supposant que cela entrerait dans un 'lambda' –

Questions connexes