Как очистить исходный SQL в Rails 4

В Rails 3 я мог бы использовать sanitize_sql_array для дезинфекции необработанного SQL для тех случайных моментов, когда необходим необработанный SQL-запрос. Но это, похоже, было удалено в Rails 4 или не так сильно удалено, но переместилось в ActiveRecord:: Sanitization. Тем не менее, я не могу понять, как называть sanitize_sql_array сейчас, так что лучший способ дезинформировать raw SQL в Rails 4?

Я хочу пояснить, что я говорю о полном сыром SQL-запросе здесь, а не о моделях Rail. Я знаю, что это не лучшая практика, это именно то, что я должен сделать для этого конкретного запроса, поскольку он не может быть представлен интерфейсом Active Record с помощью Rails (верьте мне, я пробовал).

Вот примерный вызов, который, очевидно, проще, чем выглядит мой запрос:

query = "SELECT * FROM users 
LEFT OUTER JOIN posts ON users.id=posts.user_id
AND posts.topic_id = '#{topic.id}'" 
# ^- Obviously bad and very vulnerable, this is what we're trying to fix
ActiveRecord::Base.connection.select_all(query)

Ответы

Ответ 1

Если вам действительно нужно написать сырой SQL, вы можете использовать quote для дезинфекции:

conn = ActiveRecord::Base.connection
name = conn.quote("John O'Neil")
title = conn.quote(nil)
query = "INSERT INTO users (name,title) VALUES (#{name}, #{title})"
conn.execute(query)

Ответ 2

Из Активных записей документации лучший способ дезинформировать SQL-запрос - это избежать, чтобы построить собственный условия как чистые строки, другими словами, вставляет параметры непосредственно в запрос, например:

User.find_by("user_name = '#{user_name}' AND password = '#{password}'")

и вместо этого используйте параметры массива или хэша.

Условия массива:

Client.where("orders_count = ? AND locked = ?", params[:orders], false)

Условия хеширования:

Client.where(is_active: true)

Пример пояснения:

class User < ActiveRecord::Base
  # UNSAFE - susceptible to SQL-injection attacks
  def self.authenticate_unsafely(user_name, password)
    where("user_name = '#{user_name}' AND password = '#{password}'").first
  end

  # SAFE
  def self.authenticate_safely(user_name, password)
    where("user_name = ? AND password = ?", user_name, password).first
  end

  # SAFE
  def self.authenticate_safely_simply(user_name, password)
    where(user_name: user_name, password: password).first
  end
end

Вот несколько ссылок: