如何清理 Arel SQL?

问题描述

我有以下 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 语句?

解决方法

使用 Arel.sql 通常不是处理查询的最佳方式。在我看来,您不需要清理此查询,而需要对其进行重构。

您可以使用便捷方法 orderselect 中为 rails where 子句(以及大多数其他查询方法 ArelModelName.arel_attribute(:attribute_name) 等)构建条件,这将允许您构建超出 rails 原生 where 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 属性生成所需的 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)
)
,

我正在回答我自己的问题。我正在按照 Github wiki for Ransack gem 使用 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}')"))