如何清理 Arel SQL?

How to sanitize Arel SQL?

提问人:farha 提问时间:5/4/2021 最后编辑:farha 更新时间:5/4/2021 访问量:4346

问:

我有以下 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)

如何使用 Arel 清理 sql 语句?

SQL Ruby-on-Rails SQL注入 arel

评论

0赞 tadman 5/4/2021
尝试:使用周围的数组表示法。你有什么理由去Arel而不是只使用常规的作曲方法吗?Arel.sql([ ... ])
0赞 farha 5/4/2021
当我这样做时,它给了我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
0赞 tadman 5/4/2021
这里的目标是什么?为什么不做一个简单的子句来支持占位符呢?直接使用通常是一个错误。whereArel
0赞 Sebastián Palma 5/4/2021
在某些 Rails 版本中,您可以这样做,请问使用 Arel 是否是强制性的?User.where.not(last_donated_at: nil).where('last_donated_at < ?', User::ACTIVE_DONOR_WITHIN_DAYS)
0赞 farha 5/4/2021
我正在使用 Ransack gem,它适用于 Arel 语法。如果我使用其他任何东西,我都会得到。可能有一种方法可以使它与我不知道的activerecord一起使用NoMethodError (undefined method eq

答:

1赞 engineersmnky 5/4/2021 #1

使用通常不是处理查询的最佳方式。在我看来,你不需要清理这个查询,你需要重构它。Arel.sql

你可以为 rails where 子句(以及大多数其他查询方法等)构建条件,在使用便利方法时,这将允许你构建超出 rails 原生 where 提供的高级支持的查询条件。orderselectArelModelName.arel_attribute(:attribute_name)Hash

这等同于

table_name = ModelName.arel_table
table_name[:attribute_name]

因此,让我们将其应用于您的查询:

根据您的查询,IS NOT NULL 条件没有任何意义,因为您也使用了小于,因此我们可以将条件更改为仅使用小于,例如

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

这之所以有效,是因为 NULL 不小于(或大于,甚至等于)任何值,因此这些结果不会以任何一种方式显示。

如果您坚持 IS NOT NULL 条件,我们仍然可以通过以下方式使用 Arel Atrributes 生成所需的 SQL:

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

评论

0赞 farha 5/4/2021
我正在使用 Ransack gem。我正在做一些类似于文档中提到的 #2.2 点的事情:github.com/activerecord-hackery/ransack/wiki/Using-Ransackers。如果我使用 Arel 表,我会得到undefined method 'eq' for #<Arel::Table:0x00007f928e130308>
0赞 engineersmnky 5/4/2021
@farha我不确定我是否理解你的问题。自定义 ransacker 不应包含该条件,因为 ransack 的预测将解决这个问题。除非您正在寻找布尔值,例如 true/false,在这种情况下,我也可以为此提供 Arel 解决方案
3赞 farha 5/4/2021 #2

我正在回答我自己的问题。我正在按照 Ransack gem 的 Github wiki 使用 Arel。我正在做一些与文档中提到的 #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}')"))