如何从现有 ActiveRecord_Relation 中获取 where 表达式中使用的列?

How can I get the columns used in the where expression from an existing ActiveRecord_Relation?

说我的很多模型都实现了 class 方法 self.foo 其中 returns a ::ActiveRecord_Relation.

从代码的其他地方,我可以访问该方法返回的模型或 ::ActiveRecord_Relation,我想找出查询中的 where 表达式中使用了哪些列。

如果查询很简单,我可以从 ActiveRecord_Relation 上的 where_values_hash 获取它,但我无法弄清楚如何在更复杂的查询中获取所有列。

class A < ApplicationRecord
  def self.foo(bar)
    where(column1: bar)
  end
end

class B < ApplicationRecord
  def self.foo(bar)
    joins(:c).
    merge(C.where(column2: bar))
  end
end

别处

# this evaluates to ["column1"] - success!
A.foo(bar).where_values_hash.keys 

# How can I get "c" or C and "column2" from B or B.foo(bar)?
# B or B.foo(bar).??? -> ["c", "column2"]

我总能从解析关系的 .to_sql 字符串中得到它,但必须有更好的方法。

where_values_hash 方法采用一个参数,该参数是您想要 where 子句列的 table。如果你想要所有这些,你可以用 Arel 做一些事情来获得所有加入的 tables where_values_hash。唯一的技巧是您可能希望保留 table 列来自的上下文。

def join_where_values(relation)
  relation.arel.join_sources.map do |r|
    { r.left.name => relation.where_values_hash(r.left.name) }
  end
end

{ 'b' => B.foo(bar).where_values_hash, 'joins' => join_where_values(B.foo(bar)) }