如何将多个变量清除到SQL查询ActiveRecord Rails中



在我们的应用程序中,Recipe模型有许多成分(使用:through实现的多对多关系(。有一个查询可以返回包含列表中至少一种成分的所有配方(使用ILIKESIMILAR TO子句(。我想提出两个问题:

  1. 编写查询的最干净的方法是什么?它将在带有ActiveRecord的Rails6中返回该查询。以下是我们的结局
ingredients_clause = '%(' + params[:ingredients].map { |i| i.downcase }.join("|") + ')%'
recipes = recipes.where("LOWER(ingredients.name) SIMILAR TO ?", ingredients_clause)

请注意,recipes在此点之前已经创建。

然而,这是一个有点肮脏的解决方案。我还尝试使用ILIKE=any(array['ing1','ing2',..](和以下内容:

ingredients_clause =  params[:ingredients].map { |i| "'%#{i}%'" }.join(", ")  
recipes = recipes.where("ingredients.name ILIKE ANY(ARRAY[?])", ingredients_clause)

这不起作用,因为?会自动添加单引号CCD_ 7,这当然是错误的。

这里,?用于清除SQL查询的参数,从而避免可能的SQL注入攻击。这就是为什么我不想写一个由params组成的普通查询。

有更好的方法吗?

  1. 根据匹配的成分数量订购结果的最佳方法是什么?例如,如果我搜索所有包含成分ing1ing2的食谱,它应该在只包含一种成分的食谱之前返回包含两者的食谱

提前感谢

对于#1,可能的解决方案如下(假设ingredients表已经加入(:

recipies = recipies.where(Ingredients.arel_table[:name].lower.matches_any(params[:ingredients]))

你可以在这里找到更多关于这类主题的讨论:Rails模型中的不区分大小写搜索

您可以通过#arel_table访问许多优秀的SQL查询功能。

#2如果我们假设所有where子句已经应用于recipies

recipies = recipies
.group("recipies.id")
# Lets Rails know you meant to put a raw SQL expression here
.order(Arel.sql("count(*) DESC"))

最新更新