Schienen: So finden Sie ein Feld, das eine bestimmte Zeichenfolge enthält

74

Ich habe ein Modell namens Topic, das einen Namen als Feld hat.

Sagen wir also, ich habe einen Begriff, nach dem ich suche, Apfel.

Wenn ich a mache

Topic.find_by_name("apple")

Ich bekomme eine Platte mit dem Namen Apfel zurück. Das ist gut - aber wie ändere ich find_by_name so, dass es sowohl "Apfelsaft" als auch "Apfel" findet - im Grunde Namen finden, die die ursprüngliche Abfrage enthalten oder genau mit der ursprünglichen Abfrage übereinstimmen?

Edit: Danke für die Antwort. Ich denke, ich hätte früher etwas klarer sein sollen, aber was ist, wenn ich unter einem Variablennamen suchen möchte (natürlich werde ich nicht jedes Mal unter dem Namen "Apfel" suchen wollen :))?

Wie manipuliere ich Topic.where, um dies zu berücksichtigen? Also so etwas wie ...

@topic = Topic.where(......., @name)
varatis
quelle
Ich habe meiner Antwort eine Bearbeitung hinzugefügt, die sich auf Ihre letzte Bearbeitung bezieht. Lassen Sie mich wissen, ob dies hilft!
Deleteman
In meinem Kommentar zur Antwort von @ Alisher finden Sie Antworten auf Ihre bearbeitete Frage. Topic.where("name like ?","#{@name}%")wäre eine Möglichkeit.
Tom Harrison

Antworten:

147

Ich denke so etwas sollte funktionieren:

Topic.where("name like ?", "%apple%")

So passen Sie sich Ihrer Bearbeitung an:

Topic.where("name like ?", "%#{@search}%")

Bei der einfachen String-Interpolation verwenden Sie den Wert von @searchinnerhalb des Strings %%, sodass @search = "apple"Sie am Ende den Wert erhalten%apple%

Deleteman
quelle
2
Denken Sie, dass diese Methode zur SQL-Injection führt?
Aswin Ramakrishnan
2
Soweit ich hier sagen kann, whereschützt die Methode nicht vor SQL-Injection. Die Frage kann jedoch nur dann wirklich beantwortet werden, wenn berücksichtigt wird, ob diese Variable jemals Benutzereingaben ausgesetzt ist, entweder über einen gespeicherten nicht bereinigten Wert oder direkt. Das sollte die Frage des Interesses sein. Der beste Weg, um der SQL-Injection entgegenzuwirken, besteht darin, die Werte bei der Anwendungseingabe bereits vor der Speicherung zu bereinigen.
GKnight
Wie wäre es, wenn Sie keine bestimmte Zeichenfolge enthalten?
zx1986
3
Rails verhindert die SQL-Injection, solange Sie das? für das Argument wie oben gezeigt. Sie würden offen bleiben, wenn Sie stattdessen "Name wie% @ search%" verwenden würden.
bkunzi01
1
@ bkunzi01 ist richtig, wie inguides.rubyonrails.org/… und guide.rubyonrails.org/security.html#sql-injection
Fabrizio Bertoglio
11

Mit PostgreSQL können Sie auch Match-Operatoren verwenden :

Topic.where("name ~* ?", @search)
Szymon Rut
quelle
10

Sieht so aus, als würden Sie in Rails 3 Folgendes verwenden:

Topic.where("name ILIKE ?", "%apple%")
ScottJShea
quelle
1
Nicht sicher, ob dies funktionieren würde - ist "~ =" gültige SQL? Oder denken Sie an den Ruby Pattern Matcher "= ~"? Wenn ja, würde es hier nicht funktionieren, da es nicht SQL ist
Michael Durrant
Ja, ich habe bemerkt, dass ich in dem Beitrag, auf den ich verwiesen habe, ihn zum Nennwert genommen habe ... Ich werde zu LIKE wechseln und in Sicherheit sein. Vielen Dank!
ScottJShea
5
Der ~=Operator arbeitet für PostgreSQL - es ist eine Regex-Übereinstimmung. Aber ja, Scotts Antwort sollte funktionieren. Möglicherweise möchten Sie ILIKE verwenden, bei dem die Suche ohne Berücksichtigung der Groß- und Kleinschreibung erfolgt.
Tom Harrison
9

Setzen Sie den String nicht direkt so ein. Es heißt SQL-Injection. Sie sollten stattdessen verwenden .where:

Topic.where("name like '?%' ", params[:name])
Alisher Ulugbekov
quelle
Soll das "Name wie '?%'" Oder "Name wie '%?%'"
Sein
3
Dies funktioniert nicht genau wie angegeben, da Rails die Zeichenfolge automatisch in Anführungszeichen setzt. Sie müssen zum %Beispiel vor der Auswechslung Topic.where("name like ?", "#{params[:name]}%").
Tom Harrison
Schöne Antwort. 😎
Mario Zigliotto
2

Versuchen

Topic.where("name like ?",'%apple%')
Topic.find(:all, :conditions => ["name like ?","%apple%"])
asitmoharna
quelle
SQL-Injection im ersten Beispiel sollte sein Topic.where("name like ?","%apple%"). Der zweite ist in Ordnung.
Tom Harrison
2
Sie können dies auch in Rails 4+ tun:Topic.find_by("name like ?", "%apple%")
Paul Whitehead