Rails动态“Where”子句

3

我有一个搜索框,用户可以输入“Param1”,我的控制器包含:

Model.where('column_name LIKE ?', "%#{search_field}%")

这将被转换为:

SELECT ... FROM table WHERE column_name LIKE '%Param1%'

如果用户输入"Param1",那么这个方法就很好用。但我想让它变成逗号分隔的搜索字段。

所以,如果用户输入"Param1,param2"或"Param1,Param2,Param3",WHERE LIKE子句应该能正常工作。我的想法是基于','拆分字符串,并且不知道如何在这里构建Model.where子句,因为它可以是1个参数或4个参数。

4个回答

4

如果您正在使用PostgreSQL,可以使用ANY并传递映射参数数组:

Model.where('name LIKE ANY(array[?])', params.split(',').map { |val| "%#{val}%" })
# SELECT "models".*
# FROM "models"
# WHERE (name LIKE ANY(array['%param1%','%param2%']))

3

以下是我在一个项目中的工作内容:

values = search_field.split(',').map { |x| "%#{x}%" } # split values and add "%...%"
count = values.count # count them

# create an array of LIKE operators depending on the values counted
# if count is 2 then it will be an array: ['column_name LIKE ?', 'column_name LIKE ?']
where_sql_arr = count.times.map{'column_name LIKE ?'} 

# create the sql query joining with " OR "
# 'column_name LIKE ? OR column_name LIKE ?'
where_sql = where_sql_arr.join(' OR ') 

Model.where(where_sql, *values) # note the * before "values" to split the array into multiple arguments

3
答案使用与arieljuod的答案相同的方法,但使用Arel API而不是使用纯字符串。
values = search_field.split(',')
column_name = Model.arel_table[:column_name]
query = values.map { |value| column_name.matches("%#{value}%") }.reduce(:or)
Model.where(query)

1

拆分参数是个好主意。

conditions = "Param1,Param2,Param3, Param4".gsub(" ","").split(',')

如果不需要使用掩码或正则表达式进行搜索,则可以使用IN查询或AR:Model.where(column_name: conditions)

否则(至少在postgresql中),代码会变得稍微复杂一些。

从输入字符串构造查询字符串:

conditions = "Param1,Param2,Param3, Param4".gsub(" ","").split(',')

query = ("column_name ~* ? OR " * conditions.size)[0...-3] # 删除最后一个未终止的"OR"

最后

Model.where(query, *conditions) # splat操作符(*)将数组转换为参数列表

应该能够工作。


我相信这只有在我知道用户将输入3个参数时才有效,如果他只输入2个参数怎么办? - LutherSmi
这不会执行多个LIKE查询,而是会执行一个“column_name IN(...)”查询,仅比较相等性。 - arieljuod
@LutherSmi 参数数量可以是任意的。想法是将它们转换为一个数组,该数组被Model.where(column_name: array)接受,并生成column_name IN (...)查询。正如@arieljuod所指出的那样,这样的查询只搜索精确匹配。我添加了另一种解决方案(但仅在postgresql中进行了测试)。希望能有所帮助。 - user1201917

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接