Я знаю о подготовленных операторах, но если я использую raw SQL, у ActiveRecord есть способ вручную избежать значений?
Что-то вроде этого было бы хорошо:
self.escape("O'Malley") # O\'Malley
Я знаю о подготовленных операторах, но если я использую raw SQL, у ActiveRecord есть способ вручную избежать значений?
Что-то вроде этого было бы хорошо:
self.escape("O'Malley") # O\'Malley
Вы можете сделать:
Dude.sanitize("O'Malley")
или
Dude.connection.quote("O'Malley")
оба с одинаковым результатом: => "'O''Malley'"
Быстрое погружение в источник ActiveRecord показывает его метод "sanitize_sql_array" для дезинфекции типа [string, bind_variable[, bind_variable]]
оператора sql
Вы можете называть его напрямую:
sql = ActiveRecord::Base.send(:sanitize_sql_array, ["insert into foo (bar, baz) values (?, ?), (?, ?)", 'a', 'b', 'c', 'd'])
res = ActiveRecord::Base.connection.execute(sql)
Вы можете легко использовать камень mysql2 для этого:
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"
Или, если использовать более ранний mysql (не mysql2) gem:
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"
Это позволит вам избежать чего угодно, а затем вставить в db. Вы также можете сделать это на большинстве моделей вашего приложения rails, используя метод sanitize. Например, скажем, у вас есть модель под названием Person. Вы могли бы сделать.
Person.sanitize("O'Malley")
Это должно сделать трюк.
Если вы не хотите, чтобы дополнительные одинарные кавычки обертывали вашу строку, возникающую при использовании решения, отправленного @konus, вы можете сделать это:
Dude.connection.quote_string("O'Malley")
Это возвращает "O\'Malley"
вместо "'O\'Malley'"
Даже при Model.find_by_sql
вы все равно можете использовать форму, в которой вопросительные знаки стоят в виде экранированных значений.
Просто передайте массив, в котором первым элементом является запрос, а последующие элементы - это значения, которые нужно заменить.
Пример из документации API Rails:
Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
Если кто-то ищет более конкретный пример решения @jemminger, здесь он для объемной вставки:
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
Вот ссылка на метод sanitize_sql_array в ActiveRecord:: Base, он генерирует правильную строку запроса, избегая одиночных кавычек в строках. Например, punch_line "Не позволяйте им сбивать вас" станет "Не позволяйте им сбивать вас".