在Rails 3 / ActiveRecord中构建LIKE查询时,正确的方法来转义%%

时间:2011-04-18 23:11:21

标签: sql ruby-on-rails ruby-on-rails-3 rails-activerecord

我想将网址字段与网址前缀(可能包含百分号)匹配,例如.where("url LIKE ?", "#{some_url}%")。 什么是最多的Rails方式?

4 个答案:

答案 0 :(得分:22)

如果我理解正确,你会担心{%}出现在some_url内,这是正确的;你也应该担心嵌入式下划线(“_”),它们是“。”的LIKE版本。在正则表达式。我不认为有任何特定于Rails的方法,所以你留下了gsub

.where('url like ?', some_url.gsub('%', '\\\\\%').gsub('_', '\\\\\_') + '%')

这里也不需要字符串插值。您需要将反斜杠加倍以从数据库的字符串解析器中删除它们的含义,以便LIKE解析器看到简单的“\%”并知道忽略转义的百分号。

您应该检查日志以确保两个反斜杠通过。我通过检查irb中的内容得到了令人困惑的结果,使用五个(!)得到正确的输出,但我没有看到它的意义;如果有人确实在其中五个中看到了这个意义,那么解释性评论将会受到赞赏。

更新:Jason King慷慨地提供了对逃脱逃脱角色的噩梦的简化。这允许您指定temporary escape character,以便您可以执行以下操作:

.where("url LIKE ? ESCAPE '!'", some_url.gsub(/[!%_]/) { |x| '!' + x })

我也改用了gsub的块形式,使它不那么讨厌。

这是标准的SQL92语法,因此可以在任何支持它的数据库中使用,包括PostgreSQL,MySQL和SQLite。

将一种语言嵌入另一种语言中总是有点噩梦般的克服,而且你无法做到这一点。总是会有丑陋的小点,你只需要笑着忍受。

答案 1 :(得分:17)

从Rails版本4.2.x开始,有一个名为sanitize_sql_like的活动记录方法。因此,您可以在模型中执行以下搜索范围:

scope :search, -> search { where('"accounts"."name" LIKE ?', "#{sanitize_sql_like(search)}%") }

并调用范围,如:

Account.search('Test_%')

生成的转义sql字符串是:

SELECT "accounts".* FROM "accounts" WHERE ("accounts"."name" LIKE 'Test\_\%%')

在此处阅读更多内容:http://edgeapi.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html

答案 2 :(得分:6)

https://gist.github.com/3656283

使用此代码,

Item.where(Item.arel_table[:name].matches("%sample!%code%"))

在"示例"之间正确地转义%和"代码",并匹配" AAAsample%codeBBB"但不适用于" AAAsampleBBBcodeCCC"至少在MySQL,PostgreSQL和SQLite3上。

答案 3 :(得分:-3)

Post.where('url like ?', "%#{some_url + '%'}%)