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

oka*_*56k 1 ruby postgresql ruby-on-rails ruby-on-rails-5

假设我有这样的范围:

scope :by_templates, ->(t) { joins(:template).where('templates.label ~* ?', t) }
Run Code Online (Sandbox Code Playgroud)

如何检索多个模板t

Document.first.by_templates(%w[email facebook])
Run Code Online (Sandbox Code Playgroud)

此代码返回此错误.

PG::DatatypeMismatch: ERROR:  argument of AND must be type boolean, not type record
   LINE 1: ...template_id" WHERE "documents"."user_id" = $1 AND (templates...
Run Code Online (Sandbox Code Playgroud)

mu *_*ort 5

PostgreSQL允许您使用op any(array_expr)构造将一个布尔值运算符应用于整个值数组:

9.23.3.ANY/SOME(数组)

expression operator ANY (array expression)
expression operator SOME (array expression)
Run Code Online (Sandbox Code Playgroud)

右侧是带括号的表达式,它必须产生一个数组值.评估左侧表达式并使用给定的数组的每个元素进行比较operator,这必须产生布尔结果.ANY如果获得任何真实结果,则结果为"真".如果未找到真实结果,则结果为"假"(包括阵列具有零元素的情况).

PostgreSQL还支持用于创建数组的数组构造函数语法:

array[value, value, ...]
Run Code Online (Sandbox Code Playgroud)

方便的是,当值是数组时,ActiveRecord会将占位符扩展为逗号分隔的列表.

把这些放在一起给了我们:

scope :by_templates, ->(templates) { joins(:template).where('templates.label ~* any(array[?])', templates) }
Run Code Online (Sandbox Code Playgroud)

顺便说一下,如果你使用不区分大小写的regex operator(~*)作为不区分大小写的比较(即没有真正的正则表达式模式匹配),那么你可能想要使用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
Run Code Online (Sandbox Code Playgroud)

然后,你可以添加一个索引来templatesupper(label)加快速度,并避免与杂散正则表达式元字符可能存在的问题templates.我倾向于使用大写对于这样的事情,因为古怪的谎言'ß'.upcase'SS',但'SS'.downcase作为'ss'.