2014-06-20 7 views
5

Ich implementiere ein Suchsystem, das Namen, Tags und Ort verwendet. Zwischen Server und Tag besteht eine has_and_belongs_to_many Beziehung. Hier ist, was zur Zeit meine Suchmethode wie folgt aussieht:ActiveRecord has_and_belongs_to_many: finde Modelle mit allen angegebenen Elementen

def self.search(params) 
    @servers = Server.all 

    if params[:name] 
    @servers = @servers.where "name ILIKE ?", "%#{params[:name]}%" 
    end 

    if params[:tags] 
    @tags = Tag.find params[:tags].split(",") 
    # How do I eliminate servers that do not have these tags? 
    end 

    # TODO: Eliminate those that do not have the location specified in params. 
end 

Die Tags Parameter ist nur eine durch Kommata getrennte Liste von IDs. Meine Frage wird in einem Kommentar in der if params[:tags] bedingten Block angegeben. Wie kann ich Server eliminieren, auf denen die Tags nicht angegeben sind?

Bonusfrage: Gibt es eine Möglichkeit, dies zu beschleunigen? Alle Felder sind optional und ich verwende ausschließlich Postgres.

EDIT

fand ich einen Weg, dies zu tun, aber ich habe Grund zu glauben, dass sie sehr langsam laufen. Gibt es irgendeinen Weg, der schneller ist als das, was ich getan habe? Vielleicht eine Möglichkeit, die Arbeit der Datenbank zu erledigen?

tags = Tag.find tokens 
servers = servers.reject do |server| 
    missing_a_tag = false 

    tags.each do |tag| 
     if server.tags.find_by_id(tag.id).nil? 
      missing_a_tag = true 
     end 
    end 

    missing_a_tag 
end 
+0

Wie Tags mit Servern verbunden sind, meine ich die Assoziation? –

+0

Beide haben has_and_belongs_to_many und verwenden eine Join-Tabelle namens servers_tags. –

+0

Mit "eliminieren" meinst du zerstören (d. H. Aus der Datenbank entfernen)? –

Antwort

5

Rufen Sie die Server mit allen gegebenen Tags mit

if params[:tags] 
    tags_ids = params[:tags].split(',') 
    @tags = Tag.find(tags_ids) 
    @servers = @servers.joins(:tags).where(tags: {id: tags_ids}).group('servers.id').having("count(*) = #{tags_ids.count}") 
end 

Der group(...).having(...) Teil der Server mit allen angeforderten Tags auswählt. Wenn Sie nach Servern suchen, die mindestens eines der Tags haben, entfernen Sie es.

Mit dieser Lösung wird die Suche in einer einzigen SQL-Anfrage durchgeführt, so dass es besser als Ihre Lösung ist.

+0

Leider funktioniert das nicht richtig. Es gibt keine Server zurück, obwohl Server mit dem Tag vorhanden sind. –

Verwandte Themen