将数组值发送到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):名称LIKE? 或者说喜欢? 我尝试使用params_list作为字符串,但也没有更好的工作。 我对ruby很新。

我使用以下代码为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。 ANY / SOME(数组)

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

右侧是带括号的表达式,它必须产生一个数组值。 计算左侧表达式并使用给定运算符与数组的每个元素进行比较,这必须产生布尔结果。 如果获得任何真实结果,则ANY的结果为“true”。 如果未找到真实结果,则结果为“假”(包括arrays具有零元素的情况)。

这意味着您可以像这样构建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) 

您还可以将单个'a b'输入转换为'a', 'b'是抛出一个splitflatten到混合中:

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

您可以轻松实现这一目标:

 def self.search(string) terms = string.split(' ') # split the string on each space conditions = terms.map{ |term| "name ILIKE #{sanitize("'%#{term}%'")}" }.join(' OR ') return self.where(conditions) end 

这应该是灵活的:无论字符串中的术语数量是多少,它都应该返回与至少一个术语匹配的对象。

说明:

条件是使用“ ILIKE ”,而不是“ LIKE ”:

  • ILIKE ”不区分大小写
  • LIKE ”区分大小写。

sanitize("'%#{term}%'")部分的目的如下:

  • sanitize()将阻止SQL注入,例如放置’; DROP TABLE用户;’ 作为搜索的输入。

用法:

 User.search('Michael Mich Mickey') # can return