Ruby on Rails部署至Heroku后搜索栏失效问题排查
嘿,这个问题我之前帮好几个开发者踩过坑——核心就是本地用的SQLite和Heroku上的PostgreSQL对数据类型的严格程度完全不一样!
为什么会报错?
你看到的PG::UndefinedFunction: ERROR: operator does not exist: integer ~~* unknown错误,翻译过来就是:PostgreSQL找不到“整数类型和未知类型(这里是你输入的搜索字符串)做模糊匹配”的操作符。
SQLite是出了名的“宽松”,当你拿字符串去和整数字段(比如id、price这类数字属性)做LIKE匹配时,它会偷偷帮你做类型转换,所以本地测试完全没问题。但PostgreSQL是强类型数据库,它不会自动做这种转换,直接就报错了。
怎么解决?
根据你的搜索需求,分两种情况处理:
1. 只需要搜索字符串类型字段
检查你Model里的搜索逻辑(比如scope或者查询方法),是不是不小心把整数字段也加进了LIKE匹配里。比如如果你的代码是这样的:
# 错误写法:把id(整数)和name(字符串)一起做LIKE匹配 def self.search(query) where("name LIKE ? OR id LIKE ?", "%#{query}%", "%#{query}%") end
直接去掉对整数字段的LIKE匹配就行,改成只针对字符串字段:
def self.search(query) where("name LIKE ?", "%#{query}%") end
2. 需要搜索整数字段(比如用户可能输入ID搜索)
如果确实要搜索整数字段,那得把整数字段转换成字符串类型再做匹配。在PostgreSQL里可以用::text来转换类型,同时推荐用ILIKE替代LIKE——因为PostgreSQL的LIKE是区分大小写的,而ILIKE和SQLite的LIKE行为一致(不区分大小写),这样本地和生产环境的搜索结果能更统一。
修改后的安全写法(还能避免SQL注入):
def self.search(query) where("name ILIKE :query OR id::text ILIKE :query", query: "%#{query}%") end
额外建议
为了避免以后再遇到这类环境不一致的问题,推荐本地开发环境也换成PostgreSQL。只需要修改Gemfile,把sqlite3换成pg,然后重新执行bundle install,再调整database.yml的配置即可,这样本地测试时就能提前发现这类兼容性问题。
内容的提问来源于stack exchange,提问作者Colton Van Bastelaere

