Pytanie Wywoływanie wartości w Railsach (podobne do mysql_real_escape_string ())


Wiem o przygotowanych instrukcjach, ale jeśli używam surowego SQL, czy ActiveRecord ma sposób na ręczne unikanie wartości?

Coś takiego byłoby miłe:

self.escape("O'Malley") # O\'Malley

30
2018-01-14 21:16


pochodzenie




Odpowiedzi:


Możesz to zrobić:

Dude.sanitize("O'Malley")

lub

Dude.connection.quote("O'Malley")

oba z tym samym wynikiem: => "'O''Malley'"


56
2018-02-17 05:04



Kocham twoją nazwę modelu. Dude, jesteś niesamowity. - Nate Symer
@NateSymer: Tak, cóż, to po prostu, jak, twoje zdanie, człowieku. - Darth Egregious
Jeśli ktoś się zastanawia, tak, są dokładnie tacy sami: odkaż połączenia telefoniczne - mltsy


Szybkie zanurzenie w źródle ActiveRecord ujawnia jego metodę "sanitize_sql_array" w celu odkażenia [string, bind_variable[, bind_variable]] typ instrukcji sql

Możesz zadzwonić bezpośrednio:

sql = ActiveRecord::Base.send(:sanitize_sql_array, ["insert into foo (bar, baz) values (?, ?), (?, ?)", 'a', 'b', 'c', 'd'])
res = ActiveRecord::Base.connection.execute(sql)

34
2018-02-12 15:43



Jason: To lepsze rozwiązanie, ponieważ jest niezależny od DB. Jeśli aplikacja zostanie wdrożona na Heroku, obecnie zaakceptowane rozwiązanie (@quest) nie będzie działać. - Harish Shetty
Cztery lata później, sanitize_sql_array a jego kuzyni nadal nie są częścią publicznego interfejsu API. Czy istnieje odpowiedni publiczny odpowiednik? - Jared Beck


Możesz łatwo użyć klejnotu mysql2, aby to zrobić:

irb(main):002:0> require 'rubygems'
=> true
irb(main):003:0> require 'mysql2'
=> true
irb(main):004:0> Mysql2::Client.escape("O'Malley") # => "O\\'Malley"
=> "O\\'Malley"

Lub jeśli korzystasz z wcześniejszego gem mysql (nie mysql2):

irb(main):002:0> require 'rubygems'
=> true
irb(main):003:0> require 'mysql'
=> true
irb(main):004:0> Mysql.escape_string("O'Malley")
=> "O\\'Malley"

Pozwoli ci to uciec wszystko, co chcesz, a następnie wstaw do bazy danych. Możesz to również zrobić w większości modeli w swojej aplikacji railsowej przy użyciu metody dezynfekcji. Na przykład powiedzmy, że masz model o nazwie Osoba. Mógłbyś.

Person.sanitize("O'Malley")

To powinno wystarczyć.


20
2018-02-12 06:09



Dziwne ... to była promowana odpowiedź ... potem została zmieniona ... arg. - quest
Z klejnotem Mysql2: Mysql2::Client.escape("O'Malley") # => "O\\'Malley" - Duke


Jeśli nie chcesz, aby dodatkowe pojedyncze cudzysłowy owijały twój ciąg znaków podczas używania rozwiązania opublikowanego przez @konus, możesz to zrobić:

Dude.connection.quote_string("O'Malley")

To się zwraca "O\'Malley" zamiast "'O\'Malley'"


7
2017-10-30 06:01



To nie przeszkodzi ci w wstrzyknięciu SQL. - tvdeyen
@tvdeyen: Czy byłbyś skłonny zilustrować, w jaki sposób powyższe byłoby narażone, szczególnie w porównaniu z zaakceptowaną odpowiedzią? Ostatecznie, quote_string zależy od konkretnego używanego adaptera ActiveRecord. Dla adaptera mysql2 i abstrakcyjnego adaptera mysql, quote połączenia quote_string dla ciągów wartości i zawija wynik w cudzysłowach. Czy myślisz o jakimś iniekcji wielobajtowej, czy o czymś innym? Dziękuję Ci. - Nathan
Dzięki @Nathan., To działa dla mnie .. - Breen ho


Nawet z Model.find_by_sql nadal możesz korzystać z formularza, w którym znaki zapytania występują jako wartości ewakuowane.

Wystarczy przekazać tablicę, w której pierwszym elementem jest zapytanie, a kolejne elementy to wartości do podstawienia.

Przykład z dokumentacji Rails API:

Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]

4
2018-01-14 21:20



Co jeśli wstawiam? - Jason Swett
Mogę to wykopać, ale tak naprawdę: dlaczego wstawiasz poza ActiveRelation / ActiveModel? - Andy Lindeman
Robię INSERT IGNORE i aktualizuję wiele rekordów w jednej instrukcji dla wydajności. - Jason Swett


W przypadku, gdy ktoś szuka bardziej konkretnego przykładu rozwiązania @ jemminger, tutaj jest dla wkładki zbiorczej:

users_places = []
users_values = []
timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S')
params[:users].each do |user|
    users_places "(?,?,?,?)"
    users_values << user[:name] << user[:punch_line] << timestamp << timestamp
end

bulk_insert_users_sql_arr = ["INSERT INTO users (name, punch_line, created_at, updated_at) VALUES #{users_places.join(", ")}"] + users_values
begin
    sql = ActiveRecord::Base.send(:sanitize_sql_array, bulk_insert_users_sql_arr)
    ActiveRecord::Base.connection.execute(sql)
rescue
    "something went wrong with the bulk insert sql query"
end

Tutaj jest odwołanie do metody sanitize_sql_array w ActiveRecord :: Base, generuje odpowiedni łańcuch zapytania, wymykając się pojedynczym cudzysłowom w łańcuchach. Na przykład, punch_line "Nie pozwól im się zepsuć" stanie się "Nie pozwól im się zepsuć".


2
2017-11-04 09:59