新手问题 RanSack 怎么处理英文下划线的

u1453357893 · 2016年03月04日 · 最后由 dayudodo 回复于 2018年01月12日 · 2793 次阅读

今天用到了 ransack 这个 gem,什么_cont 和_eq 用法感觉用着很爽,不过在测试搜索英文下划线时,居然把所有的 date 都检索出来了,看到发出的 sql 语句没有问题啊

User Load (0.9ms)  SELECT `users`.* FROM `users` WHERE (username like '%_%')

rails 怎么把转义字符给干掉了?不支持吗?还是没有识别?或者是没有对它处理? 于是我就自己写了个,但是自己写这个对的

User.where("username like '%\\_%'")
User Load (0.9ms)  SELECT `users`.* FROM `users` WHERE (username like '%\_%')

这是什么原因难道 ransack 没有对"_"处理吗? 我想不能每次都是手写一条针对特殊字符处理的 sql 把,有什么好的解决办法吗?请大神指点

和 rails 和 ransack 无关。是数据库查询语句的原因。

SQL pattern matching enables you to use "" to match any single character and "%" to match an arbitrary number of characters (including zero characters) _ 会被识别成通配符,所以就把所有的数据查出来了。所以,真要限制查,那只能自己加转移符号了

@pathbox 那您的意思是没办法在 rails 层处理了吗?如果处理的话,必须是对特殊字符进行特殊处理吗?就像如果遇到英文下划线时要另外的发送一条 sql 才能处理吗?那这也太 low 了吧

这是个被低估的问题。_ 是 SQL like 的通配符,Rails(包括 Sequeel 和 Ransack)默认不做处理,但提供了你一个方法 sanitize_sql_like 自己转换。

sanitize_sql_like(string, escape_character = "\") Sanitizes a string so that it is safe to use within an SQL LIKE statement. This method uses escape_character to escape all occurrences of “", ”_“ and ”%“

q = User.sanitize_sql_like("_")
User.where("username like ?", "%#{q}%")

其他方法看这里:http://stackoverflow.com/questions/5709887/a-proper-way-to-escape-when-building-like-queries-in-rails-3-activerecord

#3 楼 @ericguo 你说的具体是更新 gem 的版本吗?

#4 楼 @darkbaby123 之前也遇到过类似的问题,如你所说的,我用 model 调用了 sanitize_sql_like 的方法,可是抛出了:NoMethodError 错误,这是为什么?

#6 楼 @darkbaby123 我也有同样的疑问

@u1453357893 @easonlovewan 估计跟版本有关,这个方法是 4.2.1 加入的,在 ActiveRecord::Sanitization::ClassMethods 里面。

这样或许更简单,而且 PostgreSQL, MySQL、SQLite 都支持,是 SQL92 语法。不管是哪个版本的 rails, 只要数据库支持就可用!

User.where("username like ?escape '/' ", "%/_%")

生成的 SQL 语句是这样的:

SELECT "users".* FROM "users" WHERE (username like '%/_%' escape '/' )

escape 定义了 SQL 语句中的转义符,此句中是/, 这样下划线就不会作为通配符使用,而只是普通的符号,你也可以使用其它符号作为转义符,比如&,! 等等,例:

User.where("username like ?escape '!' ", "%!_%")
User.where("username like ?escape '&' ", "%&_%")

语句中的%因为没有转义符,所以仍然是通配符的作用,想以%作为字符可以这样:

User.where("username like ?escape '&' ", "%&%%") #=>搜索所有用户名称中包括字符%的记录
需要 登录 后方可回复, 如果你还没有账号请 注册新账号