将数组值发送到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'
是抛出一个split
并flatten
到混合中:
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