2

问题

我正试图围绕 arel 和 squeel 展开思考,但我觉得我缺乏向 Google 询问我在寻找什么的词汇。

TL;DR:有谁知道如何Model.where{related.objects.field.matches string}从组合对象中模仿 Squeel 的语法Squeel::Node

问题

这个问题演示了如何从字符串构建 Squeel KeyPath,如下所示:

search_relation = 'person.pets'
User.joins{Squeel::Nodes::KeyPath.new(search_relation.split('.'))}
# Mimics User.joins{person.pets}

在这篇文章中,情节变得更加深入,在那里我学习了如何对多列的搜索进行元编程。使用记录在案的Squeel 技巧(页面上的最后一行)进行清理,它看起来像这样:

search_columns = %w[first_name last_name]
search_term = 'chris'
User.where{
  search_columns.map do |column|
    column_stub = Squeel::Nodes::Stub.new(column)
    Squeel::Nodes::Predicate.new(column_stub, :matches, "%#{search_term}%")
  end.compact.inject(&:|)
}
# Mimics User.where{(last_name.matches '%chris%') | (first_name.matches '%chris%')} 

我想要的是能够将两者结合起来,模仿

User.joins{person.pets}.where{person.pets.name.matches '%polly%'}

通过自己构建 squeel 对象。

第一部分很简单,在第一个示例中进行了演示。第二部分我可以直接对正在查询的表上的列进行操作,如第二个示例所示。

但是,我不知道如何对表中加入的列执行第二部分。我想我需要使用第一个示例中的对象来确定第二个示例中KeyPath的对象范围Predicate。该Predicate对象似乎仅适用于Stub表示单个表上的单个列的对象,而不是KeyPath.

以前的尝试

假设

search_relation = 'key.path'
search_column = 'field'
search_term = '%search%'
keypath = Squeel::Nodes::KeyPath.new(search_relation.split('.') << search_column)

我尝试matches在 KeyPath 上调用该方法:

Model.where{keypath.matches search_term}
#=> NoMethodError: undefined method `matches' for Squeel::Nodes::KeyPath

我试过使用匹配运算符,=~

Model.where{keypath =~ search_term}
#=> TypeError: type mismatch: String given

我试过Predicate手动构建,传入一个:matches参数:

Model.where{Squeel::Nodes::Predicate.new(keypath, :matches, search_term)}
#=> ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column
#=>   'model.key.path.field' in 'where clause':
#=>   SELECT `model`.* FROM `model`
#=>     INNER JOIN `key` ON `key`.`id` = `model`.`key_id`
#=>     INNER JOIN `path` ON `path`.`id` = `key`.`path_id`
#=>     WHERE `model`.`key.path.field` LIKE '%search%'

在这里,它成功生成了 SQL(使用Model.joins{search_relation}上面的方法正确连接,为便于阅读而省略),然后假定它KeyPath是一个字段而不是遍历它。

4

2 回答 2

2

克里斯,

你在正确的轨道上。只需在 KeyPath 对象上调用matches 方法,就会创建一个matches 谓词,其中keypath 在左侧,matches 的参数在右侧。Squeel 的访问者将遍历左侧的键路径,到达有问题的属性,并针对它构建匹配的 ARel 谓词。

于 2012-11-27T13:19:10.157 回答
1

虽然KeyPath第一个示例中的 足以连接表,但KeyPath要在WHERE子句中使用的 a 需要更仔细地构造,确保最后一个值确实是 a Stub

search_relation = 'key.path'
search_column = 'field'
search_stub = Squeel::Nodes::Stub(search_column)
search_term = '%search%'
keypath = Squeel::Nodes::KeyPath.new(search_relation.split('.') << search_stub)

Model.where{Squeel::Nodes::Predicate.new(keypath, :matches, search_term)}
#=> SELECT `model`.* FROM `model`
#=>   INNER JOIN `key` ON `key`.`id` = `model`.`key_id`
#=>   INNER JOIN `path` ON `path`.`id` = `key`.`path_id`
#=>   WHERE `path`.`field` LIKE '%search%'
于 2012-11-27T18:06:28.510 回答