2010-07-13 2 views
1

J'ai une recherche assez compliquée que j'essaie de faire dans Rails et je ne suis pas tout à fait sûr de savoir comment quelqu'un peut vous aider.Comment trouver tous les articles non liés à un autre modèle - Rails 3

J'ai deux modèles, utilisateur et lieu.

Un utilisateur est lié à Place deux fois. Une fois pour visited_places et une fois pour planned_places. C'est une relation de plusieurs à plusieurs, mais en utilisant has_many: through. Voici la relation de l'utilisateur.

has_many :visited_places 
has_many :visited, :class_name=>"Place", :through=>:visited_places, :source=>:place 

has_many :planned_places 
has_many :planned, :class_name=>"Place", :through=>:planned_places, :source=>:place 

En place, la relation est également définie. Voici la définition il

has_many :visited_users, :class_name=>"User", :through=>:visited_places 
has_many :planned_users, :class_name=>"User", :through=>:planned_places 

Je suis en train d'écrire une découverte sur la place qui retourne tous les lieux dans la base de données qui ne sont pas liées à un utilisateur soit par visite ou prévu. En ce moment, j'accomplis cela en interrogeant simplement tous les lieux, puis en soustrayant visité et prévu à partir des résultats, mais je veux ajouter à la pagination et je suis inquiet que cela pourrait compliquer cela. Voici mon code actuel.

all_places = Place.find(:all)   
all_places = all_places - user.visited - user.planned 

Tout le monde sait comment je peux accomplir cela dans un simple appel à Place.find. Aussi, il s'agit d'une application Rails 3, donc si l'une des améliorations apportées à l'enregistrement actif rend cela plus facile, ils sont une option.

+0

OT, mais vous pouvez renommer votre modèle joindre - Semble votre: visited_places joindre modèle devrait être renommé « PlaceVisits », et vous pouvez avoir 'has_many: place_visits' et 'has_many: visits_places,: through =>: place_visits' –

Répondre

2

Que diriez-vous quelque chose comme:

unvisited_places = Place.find(:all, :conditions => "id NOT IN(#{visited_places.map(&:place_id)})") 

Voilà l'idée générale - il peut être rendu plus efficace et pratique en fonction de vos besoins finaux.

+0

Généralement, cela fonctionnerait, mais pour créer la liste des ID, en utilisant' visited_places.map' comme vous l'avez écrit, rails doit d'abord interroger tous les sites_visites. Il serait préférable de le faire en 1 requête, en 1 go. Laissez la base de données faire ce travail pour vous. – nathanvda

+0

Cela a fonctionné parfaitement. Merci – JoshReedSchramm

0

Vous ne le montre pas, mais si je suis juste en supposant que les modèles VisitedPlace et PlannedPlace ont une belongs_to :user relations alors ces tables ont une clé secondaire user_id, non?

Donc, dans ce cas, je pense qu'il serait plus efficace de le faire dans la base de données dans ce cas, vous êtes à la recherche d'une sélection sur une table de jointure de places, visited_places et planned_placesusers.id est pas dans l'une des visited_places ou planned_places

0

dans sql:

select * from places where id not in 
    (
    (select place_id from visited_places where user_id = ?) 
    union 
    (select place_id from planned_places where user_id=?) 
) 

Si cette requête fonctionne, vous pouvez utiliser comme suit:

Places.find_by_sql(...the complete sql query ...) 

Je ne saurais pas écrire une telle requête, avec une exclusion, dans Rails 3 sinon.

0

J'ai récemment rencontré un désir semblable ... Je voulais obtenir tous les Model1 qui n'étaient pas associés à un Model2. En utilisant Rails 4.1, voici ce que je faisais:

Model1.where.not(id: Model2.select(:user_id).uniq) 

Cela crée une commande SELECT imbriquée, comme suggéré @nathanvda, laissant effectivement la base de données faire tout le travail.Exemple SQL produit est:

SELECT "model1s".* FROM "model1s" WHERE ("model1s"."id" NOT IN (SELECT DISTINCT "model2s"."model1_id" FROM "model2s")) 
Questions connexes