将列名作为变量传递给ActiveRecord查询

时间:2019-05-24 13:16:23

标签: ruby-on-rails postgresql activerecord

假设我有一个查询:

Foo.where("lower(bar) LIKE ?", "%#{baz}%")

转换为普通SQL:

    ... WHERE (lower(bar) LIKE ...

,效果很好。但是我不想传递bar来传递参数。所以我试图这样重写它:

Foo.where("lower(?) LIKE ?", bar, "%#{baz}%")

其中bar是包含字符串'bar'的变量。在这种情况下,它将停止工作并转换为普通SQL,如下所示:

... WHERE (lower('bar') LIKE ...

那么如何使该查询起作用?

2 个答案:

答案 0 :(得分:2)

您可以通过Arel构建查询:

bar = :field_name # or 'string_name'.to_sym
Foo.where(Foo.arel_table[bar].lower.matches("%#{baz}%"))

答案 1 :(得分:1)

您可能要尝试在模板中使用sprintf样式的%转义符,以避免引用要插入的列名:

Foo.where("lower(%s) LIKE '%s'", bar, "%#{baz}%")

(N.B。第二个%s周围的单引号-第二个参数确实要用引号引起来)

Reference

  

最后,您可以在模板中使用sprintf样式的%转义符。这与以前的方法略有不同。您有责任确保正确引用模板中的值。这些值将传递到连接器以进行引用,但是调用者负责确保将它们包含在结果SQL中的引号中。引用后,使用与Ruby核心方法Kernel :: sprintf相同的转义符插入值。