Как очистить Arel SQL?

#sql #ruby-on-rails #sql-injection #arel

Вопрос:

У меня есть следующий Arel SQL:

 Arel.sql("(users.last_donated_at IS NOT NULL AND users.last_donated_at < '#{User::ACTIVE_DONOR_WITHIN_DAYS.days.ago}')")
 

Я получаю SQL Injection предупреждение, когда запускаю брейкмана. Я попробовал следующее:

 Arel.sql("(users.last_donated_at IS NOT NULL AND users.last_donated_at < ?)", User::ACTIVE_DONOR_WITHIN_DAYS.days.ago)
 

Однако я получаю следующую ошибку:

 ArgumentError:
       wrong number of arguments (given 2, expected 1)
 

Как очистить инструкцию sql с помощью Arel?

Комментарии:

1. Попробуйте: Arel.sql([ ... ]) с обозначением окружающего массива. Есть ли какая-то причина, по которой вы переходите на Arel, а не просто используете обычные методы композиции?

2. Когда я это делаю Arel.sql(["(users.last_donated_at IS NOT NULL AND users.last_donated_at < ?)", "#{User::ACTIVE_DONOR_WITHIN_DAYS.days.ago.to_s(:db)}"]) , это дает мне no implicit conversion of Array into String

3. Какова здесь цель? Почему бы не сделать простое where предложение, которое поддерживает заполнители? Arel Прямое использование обычно является ошибкой.

4. В некоторых версиях Rails вы могли бы просто сделать User.where.not(last_donated_at: nil).where('last_donated_at < ?', User::ACTIVE_DONOR_WITHIN_DAYS) , могу я спросить, является ли использование Arel обязательным?

5. Я использую Ransack gem, и он работает с синтаксисом Arel. Я получаю NoMethodError (undefined method eq , если использую что-нибудь еще. Вероятно, есть способ заставить его работать с activerecord, о котором я не знаю

Ответ №1:

Я отвечаю на свой собственный вопрос. Я использую Arel, следуя вики-сайту Github для поиска драгоценного камня. Я делал что-то очень похожее на пункт № 2.2, упомянутый в документе: https://github.com/activerecord-hackery/ransack/wiki/Using-Ransackers. Чтобы очистить параметры и избежать sql injection предупреждения тормозника, я в итоге сделал следующее:

 Arel.sql(sanitize_sql_array("(users.last_donated_at IS NOT NULL AND users.last_donated_at < '#{User::ACTIVE_DONOR_WITHIN_DAYS.days.ago}')"))
 

Ответ №2:

Использование Arel.sql , как правило, не лучший способ обработки запросов. На мой взгляд, вам не нужно очищать этот запрос, вам нужно его реорганизовать.

Вы можете создавать условия для предложения rails where (и большинства других методов запроса order и select т. Д.), Arel Используя метод удобства ModelName.arel_attribute(:attribute_name) , Это позволит вам создавать условия запроса, выходящие за рамки поддержки высокого уровня, предлагаемой собственным языком rails where. Hash

Это идентично

 table_name = ModelName.arel_table
table_name[:attribute_name]
 

Итак, давайте применим это к вашему запросу:

На основании вашего запроса условие НЕ РАВНО НУЛЮ ничего не значит, так как вы также используете меньше, чем, поэтому мы можем изменить условие, чтобы просто использовать меньше, чем, например

 User.arel_attribute(:last_donated_at).lt(User::ACTIVE_DONOR_WITHIN_DAYS.days.ago)
 

Это работает, потому что значение NULL не меньше (или больше, или даже равно) чему-либо, поэтому эти результаты не будут отображаться в любом случае.

Если вы настаиваете на условии «НЕ РАВНО НУЛЮ», мы все равно можем создать нужный SQL, используя атрибуты Arel через:

 User.arel_attribute(:last_donated_at).not_eq(nil).and(
  User.arel_attribute(:last_donated_at).lt(User::ACTIVE_DONOR_WITHIN_DAYS.days.ago)
)
 

Комментарии:

1. Я использую драгоценный камень для обыска. Я делаю что-то похожее на пункт № 2.2, как указано в документе: github.com/activerecord-hackery/ransack/wiki/Using-Ransackers . Я получаю undefined method 'eq' for #<Arel::Table:0x00007f928e130308> , если использую таблицу Арела

2. @farha Я не уверен, что понимаю вашу проблему. Пользовательские поисковики не должны включать это условие, так как предикация ransack позаботится об этом. Если вы не ищете логическое значение, например, true/false, в этом случае я также мог бы предоставить решение Arel для этого