在Ruby中向sql查询发送数组值?[英] Sending array of values to a sql query in ruby?

本文是小编为大家收集整理的关于在Ruby中向sql查询发送数组值?的处理方法,想解了在Ruby中向sql查询发送数组值?的问题怎么解决?在Ruby中向sql查询发送数组值?问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我正在努力解决似乎是 ruby​​ 语义问题.我正在编写一个方法,它从表单中获取 可变数量的参数 并创建一个 Postgresql 查询.

def self.search(params)
    counter = 0
    query = ""
    params.each do |key,value|
        if key =~ /^field[0-9]+$/
            query << "name LIKE ? OR "
            counter += 1
        end
    end
    query = query[0..-4] #remove extra OR and spacing from last

    params_list = []
    (1..counter).each do |i|
      field = ""
      field << '"%#{params[:field'
      field << i.to_s
      field << ']}%", '
      params_list << field
    end
    last_item = params_list[-1]
    last_item = last_item[0..-3] #remove trailing comma and spacing
    params_list[-1] = last_item

    if params
        joins(:ingredients).where(query, params_list)
    else
        all
    end
end

尽管 params_list 是一个数值数组,在数量上与"name LIKE?"匹配?在查询部分,我收到一个错误:绑定变量数量错误(1 对 2)在:name LIKE 中?OR name LIKE ? 我尝试使用 params_list 作为字符串,但也没有更好的效果.我对红宝石很陌生.

我使用以下代码为 2 个参数工作,但希望允许用户最多提交 5 个 (:field1, :field2, :field3 ...)

def self.search(params)
    if params
        joins(:ingredients).where(['name LIKE ? OR name LIKE ?', 
            "%#{params[:field1]}%", "%#{params[:field2]}%"]).group(:id)
    else
        all
    end
end

有人能解释一下我应该如何编程吗?

推荐答案

PostgreSQL 支持标准 SQL 数组和标准 any op (...) 语法:

<块引用>

9.23.3.任何/某些(数组)

expression operator ANY (array expression)
expression operator SOME (array expression)

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

这意味着您可以像这样构建 SQL:

where name ilike any (array['%Richard%', '%Feynman%'])

这很好而且简洁,那么我们如何让 Rails 构建它呢?这其实很简单:

Model.where('name ilike any (array[?])', names.map { |s| "%#{s}%" })

不需要手动引用,ActiveRecord 会在填充 ? 占位符时将数组转换为正确引用/转义的列表.

现在你只需要构建 names 数组.像这样简单的事情应该这样做:

fields = params.keys.select { |k| k.to_s =~ /\Afield\d+\z/ }
names  = params.values_at(*fields).select(&:present)

您还可以通过将 split 和 flatten 混合使用来将单个 'a b' 输入转换为 'a', 'b':

names = params.values_at(*fields)
              .select(&:present)
              .map(&:split)
              .flatten

本文地址:https://www.itbaoku.cn/post/1763874.html