说我有一个这样的范围:
scope :by_templates, ->(t) { joins(:template).where('templates.label ~* ?', t) }
如何像这样用t
检索多个模板?
Document.first.by_templates(%w[email facebook])
此代码返回此错误。
PG::DatatypeMismatch: ERROR: argument of AND must be type boolean, not type record
LINE 1: ...template_id" WHERE "documents"."user_id" = $1 AND (templates...
答案 0 :(得分:5)
PostgreSQL允许您使用op any(array_expr)
construct将布尔值运算符应用于整个值数组:
9.23.3。 ANY / SOME(数组)
expression operator ANY (array expression) expression operator SOME (array expression)
右侧是带括号的表达式,必须产生一个数组值。使用给定的
operator
评估左侧表达式并将其与数组的每个元素进行比较,该表达式必须产生布尔结果。如果获得任何真实结果,则ANY
的结果为“ true”。如果找不到正确的结果(包括数组具有零个元素的情况),则结果为“ false”。
PostgreSQL还支持array constructor syntax用于创建数组:
array[value, value, ...]
方便地,当值是数组时,ActiveRecord会将占位符扩展为逗号分隔的列表。
将它们放在一起可以得到:
scope :by_templates, ->(templates) { joins(:template).where('templates.label ~* any(array[?])', templates) }
顺便说一句,如果您使用不区分大小写的正则表达式运算符(~*
)作为不区分大小写的比较(即不进行实际的正则表达式模式匹配),则可能要使用{{1 }}:
upper
然后,您可以在# Yes, this class method is still a scope.
def self.by_templates(templates)
joins(:template).where('upper(templates.label) = any(array[?])', templates.map(&:upcase) }
end
的{{1}}上添加索引,以加快处理速度并避免templates
中杂散的正则表达式元字符可能出现的问题。我倾向于将大写字母用于这种情况,因为upper(label)
是templates
,而'ß'.upcase
是'SS'
。