Railsで検索機能を実装する時に、PostgreSQLとSQLiteでは、Active Recordが違う挙動を取ることを初めて知った。
以前リリースしたサービスLinch(リンク)で検索機能を実装する時に初めて分かったことをまとめておきます。
分かった問題
Railsで作ったサービスのあいまい検索の挙動がPostgreSQLとSQLiteで少し違う。(大文字・小文字の区別に関して)
具体的にどう違うのか
改善前
このサービスは、Herokuでデプロイしているので、DBはPostgreSQLを利用しています。 それに対して、ローカル環境では、SQLiteを利用するようになっています。 ここのところの挙動の違いなどを全く意識せずにコードを書いていたので、 検索機能のところのコードが下記のようになっていました。
@articles = Article.where("title like '%" + params[:q] + "%'")
検索ボックスに入力されたクエリをパラメーターとして持たせて検索するというごく普通なコードです。
ローカル環境(つまり、SQLite上)では、このコードでも大文字・小文字の区別なく検索してくれます。 しかし、本番環境(PostgreSQL上)では、大文字・小文字の区別がされてしまっていました。
例)「Python」で検索した時に、ローカルでは、「Python入門」「pythonスクレイピング」が検索結果に引っ掛かる> が、本番では、「Python入門」しか引っかからない。
解決策
解決策としては、挙げられたものは下記の二つです。
① Arel使う
@articles = Article.where(articles[:title].matches("%#{params[:q]}%"))
少し調べたところ下のような記事が出てきました。
② クエリと検索対象をどちらもdowncaseする
@articles = Article.where("lower(title) like ?", "%#{params[:q].downcase}%")
こっちの方がなんとなくActive Recordらしさがあるような気がします。
最終的に
1の方の記事を読んだ限りでは、バージョンアップによって動かなくなる可能性があるとのことだったので、 最終的には、2の方を採用しました。
まとめ
普段何の気なしに触っていたActive Recordが、使うDBによって違う挙動を示すことに気づけたことは非常に良かったと思います。また、Active Recordではなく、生のSQLと格闘する必要もありそうなので、そこらへんも勉強していこうと思います。