Rails 5范围像多个部分字符串

时间:2018-12-11 00:56:15

标签: ruby-on-rails ruby postgresql ruby-on-rails-5

说我有一个这样的范围:

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...

1 个答案:

答案 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'