Rails, как дезинфицировать SQL в find_by_sql

Есть ли способ дезинформировать sql в методе rails find_by_sql?

Я пробовал это решение: Ruby on Rails: как очистить строку для SQL, если вы не используете find?

Но он терпит неудачу при

Model.execute_sql("Update users set active = 0 where id = 2")

Он выдает ошибку, но выполняется код sql, и у пользователя с ID 2 теперь есть отключенная учетная запись.

Простой find_by_sql также не работает:

Model.find_by_sql("UPDATE user set active = 0 where id = 1")
# => code executed, user with id 1 have now ban

Edit:

Хорошо, мой клиент попросил сделать эту функцию (выберите по sql) в панели администратора, чтобы сделать сложный запрос (объединения, особые условия и т.д.). Поэтому я действительно хочу find_by_sql, что.

Второе редактирование:

Я хочу достичь этого "злого" кода SQL, который не будет выполнен.

В панели администратора вы можете ввести запрос → Update users set admin = true where id = 232, и я хочу заблокировать любую команду UPDATE/DROP/ALTER SQL. Просто хочу знать, что здесь вы можете ТОЛЬКО выполнять SELECT.

После некоторых попыток я заключаю sanitize_sql_array, к сожалению, этого не делают.

Есть ли способ сделать это в Rails?

Извините за путаницу..

Ответы

Ответ 1

Попробуйте следующее:

connect = ActiveRecord::Base.connection();
connect.execute(ActiveRecord::Base.send(:sanitize_sql_array, "your string"))

Вы можете сохранить его в переменной и использовать для своих целей.

Ответ 2

Я сделал небольшой фрагмент для этого, чтобы вы могли ввести инициализаторы.

class ActiveRecord::Base  
  def self.escape_sql(array)
    self.send(:sanitize_sql_array, array)
  end
end

Теперь вы можете избежать запроса:

query = User.escape_sql(["Update users set active = ? where id = ?", true, params[:id]])

И вы можете вызвать запрос любым способом:

users = User.find_by_sql(query)

Ответ 3

Немного более универсальный:

class ActiveRecord::Base  
  def self.escape_sql(clause, *rest)
    self.send(:sanitize_sql_array, rest.empty? ? clause : ([clause] + rest))
  end
end

Это позволяет вам называть его так же, как вы вводите предложение where без дополнительных скобок и используете либо массив-стиль? или интерполяции в стиле хэш.

Ответ 5

Хотя этот пример для запроса INSERT, можно использовать аналогичный подход для запросов UPDATE. Загрузочная вставка SQL:

users_places = []
users_values = []
timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S')
params[:users].each do |user|
    users_places << "(?,?,?,?)" # Append to array
    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 "Не позволяйте им сбивать вас" станет "Не позволяйте им сбивать вас".