在.order上修正过时警告“危险查询方法”

时间:2019-11-28 14:04:19

标签: activerecord ruby-on-rails-5 sql-order-by arel ruby-on-rails-6

我有一个自定义的gem,它使用来自Elasticsearch实例的输入来创建AR查询。

# record_ids: are the returned ids of the ES results
# order: is the order of the of the ids that ES returns

search_class.where(search_class.primary_key => record_ids).order(order)

现在,实现是将订单字符串直接构建到order变量中,因此它看起来像这样:["\"positions\".\"id\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC"] 效果很好,但会发出弃用警告,最终将在rails6中不起作用。

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "\"positions\".\"id\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC". Non-attribute arguments will be disallowed in Rails 6.0. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql()

所以我尝试了几种不同的方法,但是都没有成功。


order = ["\"positions\".\"id\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC"]

# Does not work since order is an array
.order(Arel.sql(order))

# No errors but only returns an ActiveRecord_Relation
# on .inspect it returns `PG::SyntaxError: ERROR:  syntax error at or near "["`
.order(Arel.sql("#{order}"))
# .to_sql: ORDER BY [\"\\\"positions\\\".\\\"id\\\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC\"]"

order = ['fcdc924a-21da-440e-8d20-eec9a71321a7', ...]

# Won't work since its only for integer values
.order("idx(ARRAY#{order}, #{search_class.primary_key})")
# .to_sql ORDER BY idx(ARRAY[\"fcdc924a-21da-440e-8d20-eec9a71321a7\", ...], id)

# Only returns an ActiveRecord_Relation
# on .inspect it returns `PG::InFailedSqlTransaction: ERROR:`
.order("array_position(ARRAY#{order}, #{search_class.primary_key})")
# .to_sql : ORDER BY array_position(ARRAY[\"fcdc924a-21da-440e-8d20-eec9a71321a7\", ...], id)

我有点困惑,因为将来Rails会强制使用属性参数,并且没有选择退出这一点。由于order是一个代码生成的数组,并且我可以完全控制这些值,因此我很好奇如何实现它。也许有人在提供一些有用的见解或想法之前就遇到了这个问题?

1 个答案:

答案 0 :(得分:1)

您可以尝试将Arel.sql应用于应该起作用的数组元素,即

search_class.where(search_class.primary_key => record_ids)
  .order(order.map {|i| i.is_a?(String) ? Arel.sql(i) : i})