我想将url字段与url前缀(可能包含百分号)匹配,例如.where("url LIKE ?", "#{some_url}%")
。最适合Rails的方式是什么?
来自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
如果我理解正确,您担心"%"出现在some_url
中,这是正确的;你也应该担心嵌入的下划线("_"),它们是正则表达式中"。"的LIKE版本。我不认为有任何rails特定的方式来做到这一点,所以你只剩下gsub
:
.where('url like ?', some_url.gsub('%', '\\%').gsub('_', '\\_') + '%')
这里也不需要字符串插值。您需要双反斜杠来从数据库的字符串解析器转义它们的含义,以便LIKE解析器将看到简单的"%"并知道忽略转义的百分号。
你应该检查你的日志,以确保两个反斜杠通过。我从检查irb
中的东西得到令人困惑的结果,使用五(!)得到正确的输出,但我看不出其中的意义;如果有人真的看到了其中五个的意义,请给予解释性的评论。
UPDATE: Jason King为转义转义字符的噩梦提供了一个简化。这允许您指定一个临时转义字符,以便您可以执行以下操作:
.where("url LIKE ? ESCAPE '!'", some_url.gsub(/[!%_]/) { |x| '!' + x })
我也切换到gsub
的块形式,使它不那么讨厌。
这是标准的SQL92语法,因此可以在任何支持它的数据库中工作,包括PostgreSQL, MySQL和SQLite。
将一种语言嵌入到另一种语言中总是有点像噩梦般的拼凑,而且你对此无能为力。生活中总会有一些丑陋的小细节,你只能勉强忍受。
https://gist.github.com/3656283
在这个代码中,
Item.where(Item.arel_table[:name].matches("%sample!%code%"))
正确转义"sample"one_answers"code"之间的%
,并匹配"AAAsample%codeBBB",但不为"AAAsampleBBBcodeCCC"在MySQL, PostgreSQL和SQLite3至少。
Post.where('url like ?', "%#{some_url + '%'}%)