2016-05-11 3 views
3

Ich möchte ein Post Modell finden, dessen title ist "foo", aber, wenn der Beitrag nicht existiert, "bar" und dann "Foobar".Liefert find_by immer eine Übereinstimmung zum ersten eines Array von Bedingungen, wenn möglich?

Dafür schrieb ich folgendes:

Post.find_by(title: %w(foo bar foobar)) 

Es scheint jetzt zu funktionieren gut, aber ich bin mir nicht sicher, ob die find_by Methode immer zuerst den ersten Wert in dem Array von Strings findet.

Wenn es Beiträge, deren Titel "foo" und "bar", wird der Code oben immer wieder zurückkehren an den Pfosten mit dem Titel "foo"?

Antwort

0

Die Reihenfolge der Alternativen spielt keine Rolle. Per the documentation

Sucht den ersten Datensatz, der den angegebenen Bedingungen entspricht. Es gibt keine implizite Bestellung, also wenn die Bestellung wichtig ist, sollten Sie sie selbst angeben.

Wenn Sie die Beiträge in einer bestimmten Reihenfolge möchten, haben Sie entweder

  • eine order Klausel der Abfrage hinzufügen, zum Beispiel

    Post.order("case title when 'foo' then 0 when 'bar' then 1 when 'foobar' then 2 end"). 
    find_by(title: %w(foo bar foobar)) 
    

    in MySQL getestet wurden; nicht sicher wie weit verbreitet diese Syntax ist, aber zumindest etwas ähnliches sollte in jeder SQL Datenbank verfügbar sein.

    Möglicherweise müssen Sie die order-Klausel dynamisch erstellen. Von Eisensand-Lösung in den Kommentaren:

    titles = %w(foo bar foobar) 
    order_sql = "case #{titles.map.with_index { |title, i| "when '#{title}' then #{i}" }.join ' ' } end" 
    Post.order(order_sql).find_by(title: titles) 
    
  • Abfrage alle Beiträge und sortieren sie danach

    Post.all.sort_by { |post| %w(foo bar foobar).index post.title }.first 
    

    Diese für eine große Anzahl von Stellen langsam sein, so sei es wahrscheinlich, ob Sie hängt nützlich ist kann mit etwas spezifischer als Post.all starten.

+0

'find_by' Rückkehr höchstens ein Rekord, so dass die„die Beiträge sortieren danach“ist nur eine komplizierte Art und Weise eine NoMethodError zu heben. Der 'ORDER BY CASE ...' Ansatz OTOH sollte mit jedem RDBMS funktionieren und funktionieren. –

+0

'ORDER BY CASE' kann bei mehr als 20 dynamischen Titeln schnell unbrauchbar werden. Man sollte entweder die 'order'-Klausel dynamisch erstellen oder 'Post' verwenden.wo (Titel: Titel) .sort_by'. – mudasobwa

+1

Danke! Ich werde mit dem 'ORDER BY CASE' gehen. Um die bedingte Zeichenfolge zu vereinfachen, schrieb ich wie 'titles.map.with_index {| title, i | "wenn '# {title}' dann # {i}"} .join'. – ironsand

0

Zu diesem

Post.find_by(title: %w(foo bar foobar)) 

die SQL-Abfrage laufen als

SELECT "posts".* FROM "posts" WHERE "posts"."title" IN ('foo', 'bar', 'foobar') LIMIT 1 

die Abfrage enthält eine Grenze Einschränkung, so dass Sie nur einen Datensatz obwohl die Bedingung erfüllt, erhalten wird.

Sie verwenden sollten, wo Abfrage alle Recors zu bekommen

Post.where(title: %w(foo bar foobar))