我正试着把头包裹起来,但是我觉得我缺乏词汇来询问Google我在寻找什么。
TL; DR:有谁知道如何模仿Squeel的Model.where{related.objects.field.matches string}
语法来组成Squeel::Node
个对象?
This question演示了如何从字符串构建Squeel KeyPath,如下所示:
search_relation = 'person.pets'
User.joins{Squeel::Nodes::KeyPath.new(search_relation.split('.'))}
# Mimics User.joins{person.pets}
情节在this post中变浓,在那里我学习了如何跨多个列对一个搜索进行元编程。使用documented Squeel trick(页面的最后一行)清理,它看起来像这样:
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%'}
自己建造吱吱声物体。
第一部分很简单,在第一个例子中进行了演示。第二部分我可以直接对正在查询的表上的列进行操作,在第二个示例中进行了演示。
但是,我无法弄清楚如何为表中连接的列执行第二部分。我想我需要使用第一个示例中的KeyPath
对象来限定第二个示例中的Predicate
对象。 Predicate
对象似乎只与Stub
对象一起使用,该对象代表单个表上的单个列,而不是KeyPath
。
Assumming
search_relation = 'key.path'
search_column = 'field'
search_term = '%search%'
keypath = Squeel::Nodes::KeyPath.new(search_relation.split('.') << search_column)
我尝试在KeyPath上调用matches
方法:
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
是一个字段而不是遍历它。
答案 0 :(得分:2)
克里斯,
你走在正确的轨道上。只需在KeyPath对象上调用matches方法,就会创建一个匹配谓词,左边是keypath,右边是匹配的参数。 Squeel的访问者将遍历左侧的密钥路径,到达相关属性,并根据它建立匹配ARel谓词。
答案 1 :(得分:1)
虽然第一个示例中的KeyPath
足以连接表,但是需要通过确保最后一个值来更加谨慎地构建要在KeyPath
子句中使用的WHERE
确实是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%'