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

发布于 2024-11-01 20:18:07 字数 108 浏览 1 评论 0原文

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

I want to match a url field against a url prefix (which may contain percent signs), e.g. .where("url LIKE ?", "#{some_url}%").
What's the most Rails way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

再见回来 2024-11-08 20:18:07

从 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

From Rails version 4.2.x there is an active record method called sanitize_sql_like. So, you can do in your model a search scope like:

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

and call the scope like:

Account.search('Test_%')

The resulting escaped sql string is:

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

Read more here: http://edgeapi.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html

转瞬即逝 2024-11-08 20:18:07

如果我理解正确的话,您担心“%”出现在 some_url 中,这是正确的;您还应该担心嵌入的下划线(“_”),它们是“.”的类似版本。在正则表达式中。我认为没有任何特定于 Rails 的方法可以做到这一点,因此您只剩下 gsub:

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

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

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

更新:杰森·金(Jason King)善意地为逃脱角色的噩梦提供了简化。这可以让你指定一个临时转义字符,这样你就可以做一些事情像这样:

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

我还切换到了 gsub 的块形式,以使其不那么令人讨厌。

这是标准 SQL92 语法,因此适用于任何支持该语法的数据库,包括 PostgreSQL、MySQL 和 SQLite。

将一种语言嵌入另一种语言总是有点噩梦般的混乱,对此您无能为力。总会有一些丑陋的小事,你只能微笑着忍受。

If I understand correctly, you're worried about "%" appearing inside some_url and rightly so; you should also be worried about embedded underscores ("_") too, they're the LIKE version of "." in a regex. I don't think there is any Rails-specific way of doing this so you're left with gsub:

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

There's no need for string interpolation here either. You need to double the backslashes to escape their meaning from the database's string parser so that the LIKE parser will see simple "\%" and know to ignore the escaped percent sign.

You should check your logs to make sure the two backslashes get through. I'm getting confusing results from checking things in irb, using five (!) gets the right output but I don't see the sense in it; if anyone does see the sense in five of them, an explanatory comment would be appreciated.

UPDATE: Jason King has kindly offered a simplification for the nightmare of escaped escape characters. This lets you specify a temporary escape character so you can do things like this:

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

I've also switched to the block form of gsub to make it a bit less nasty.

This is standard SQL92 syntax, so will work in any DB that supports that, including PostgreSQL, MySQL and SQLite.

Embedding one language inside another is always a bit of a nightmarish kludge and there's not that much you can do about it. There will always be ugly little bits that you just have to grin and bear.

木格 2024-11-08 20:18:07

https://gist.github.com/3656283

使用此代码,

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

正确转义“sample”和“code”之间的 %,并匹配“AAAsample%codeBBB”,但是做至少不适用于 MySQL、PostgreSQL 和 SQLite3 上的“AAAsampleBBBcodeCCC”。

https://gist.github.com/3656283

With this code,

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

correctly escapes % between "sample" and "code", and matches "AAAsample%codeBBB" but does not for "AAAsampleBBBcodeCCC" on MySQL, PostgreSQL and SQLite3 at least.

ˇ宁静的妩媚 2024-11-08 20:18:07
Post.where('url like ?', "%#{some_url + '%'}%)
Post.where('url like ?', "%#{some_url + '%'}%)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文