5

Ich bin seit einiger Zeit verwirrt über den Unterschied zwischen der Verwendung eines Fragezeichens, z.Was ist der Unterschied zwischen der Verwendung? und% beim Desinfizieren von Feldern in ActiveRecord?

Foo.find(:all, :conditions => ['bar IN (?)', @dangerous]) 

und unter Verwendung von Sprintf-Stil-Feldtypen, z.

Bar.find(:all, :conditions => ['qux IN (%s)', @dangerous]) 

in Desinfektionseingängen. Gibt es irgendeinen Sicherheitsvorteil, wenn Sie wissen, dass Sie nach einer Zahl suchen - wie einer ID - und nicht nach einer Zeichenkette,% d über verwenden? Oder fragen Sie einfach nach einem Big Nasty Error, wenn stattdessen eine Zeichenkette erscheint ?

Ändert sich das überhaupt mit der neueren .where-Syntax in Rails 3 und 4?

+0

ich wusste nicht einmal, dass dies in rails2 möglich ist – phoet

+1

@muistooshort, es scheint zumindest in Rails 3 funktioniert. Guter Punkt über zukünftige Proofing, da es nirgendwo dokumentiert scheint. –

+0

In 3+ würde ich 'where (: bar => @dangerous)' auf jeden Fall sagen, das wird das Richtige tun, wenn '@ dangerous' ein nicht-leeres Array ist (aber ach, [etwas dummes] (http://stackoverflow.com/a/12946338/479863) wenn es ein leeres Array ist). –

Antwort

1

%s ist für Strings vorgesehen. Der Hauptunterschied besteht darin, dass %s keine Anführungszeichen hinzufügt. Von ActiveRecord::QueryMethods.where:

Lastly, you can use sprintf-style % escapes in the template. This works slightly differently than the previous methods; you are responsible for ensuring that the values in the template are properly quoted. The values are passed to the connector for quoting, but the caller is responsible for ensuring they are enclosed in quotes in the resulting SQL. After quoting, the values are inserted using the same escapes as the Ruby core method Kernel::sprintf .

Beispiele:

User.where(["name = ? and email = ?", "Joe", "[email protected]"]) 
# SELECT * FROM users WHERE name = 'Joe' AND email = '[email protected]'; 

User.where(["name = '%s' and email = '%s'", "Joe", "[email protected]"]) 
# SELECT * FROM users WHERE name = 'Joe' AND email = '[email protected]'; 

Update:

Sie sind ein Array übergeben. %s scheint Anrufe .to_s auf das Argument, so könnte dies nicht funktioniert wie erwartet:

User.where("name IN (%s)", ["foo", "bar"]) 
# SELECT * FROM users WHERE (name IN ([\"foo\", \"bar\"])) 

User.where("name IN (?)", ["foo", "bar"]) 
# SELECT * FROM users WHERE (name IN ('foo','bar')) 

Für einfache Abfragen Sie die Hash-Notation verwenden:

User.where(name: ["foo", "bar"]) 
# SELECT * FROM users WHERE name IN ('foo', 'bar') 
+0

Es geht nicht nur um Zitate.% s scheint in eine Zeichenkette zu konvertieren, egal, was Sie darauf werfen, und das Ergebnis wird wie in der Abfrage platziert. Nein, nein. Bitte sehen Sie auch meine Antwort. – Giuseppe

+0

@Giuseppe du hast Recht, ich habe übersehen, dass das OP ein Array an '% s' übergeben. – Stefan

+0

Ich denke, der Hauptvorzug hier ist, dass "% s" ** nicht zitiert und daher nicht wirklich nützlich für die Desinfektion ist. Es entgeht jedoch, also ist es auch nicht nutzlos. '@ dangerous' müsste nicht unbedingt ein Array sein. Es könnte eine Kette von durch Komma getrennten Werten sein, z. '@dangerous =" 1, 2, 3 "' –

1

Soweit ich, %s einfach Einsätze sagen kann, in Ihre Anfrage was auch immer @dangerous.to_s passiert, und Sie sind dafür verantwortlich.

Zum Beispiel, wenn @dangerous ist ein Array von ganzen Zahlen, dann werden Sie eine SQL-Fehlermeldung erhalten:

@dangerous = [1,2,3] 
User.where("id IN (%s)", @dangerous) 

in der folgenden falschen Syntax führen wird:

SELECT `users`.* FROM `users` WHERE (id IN ([1, 2, 3])) 

während:

User.where("id IN (?)", @dangerous) 

erzeugt die richtige Abfrage:

SELECT `users`.* FROM `users` WHERE (id IN (1,2,3)) 

So ist scheint mir, dass, wenn Sie sehr einfach, sehr gut, was Sie tun, sollten Sie die ? Bediener seine Arbeit tun lassen, vor allem, wenn Sie den Inhalt @dangerous als sicher nicht vertrauen.

+0

Es scheint, dass '% s' entkommt, also ist es" sicher ", aber weil es nicht zitiert, könnte es unerwartete Ergebnisse, einschließlich Fehler, haben. Sie sind richtig, wahrscheinlich am besten, es zu vermeiden, es sei denn, man hat einen sehr guten Grund, dies zu tun. 'Foo.where (" bar =? ", @ Dangerous.to_s)' würde das gleiche erreichen, aber mit weniger Bedenken, korrekt zu zitieren. Aber selbst das ist wahrscheinlich unnötig und vielleicht sogar die meiste Zeit unerwünscht. –

Verwandte Themen