概要
データを更新する処理を行なった際に、
検索条件に"_"が入ることで予期せぬデータを書き換えてしまいました。
問題となったコード
Brandテーブルのnameカラムが"_"のものだけ、"ユニクロ"に変更したいというコードです。
Brand.where("name LIKE?", "_").update_all(name: "ユニクロ")
どこが間違っているか
Brand.where("name LIKE?", "_")
で検索すると、
"_"のものだけではなく、
数字1文字のものや、漢字1文字のものなどにもヒットしてしまいます!
理由
SQL LIKEワイルドカード(つまり、%と_)はエスケープされません
とあるように、
検索条件の_
は任意の1文字全てにヒットしてしまうからです。
対策
sanitize_sql_like
を使用して、
引数のワイルドカード文字をエスケープしましょう。
Brand.where("name LIKE?", Brand.sanitize_sql_like("_"))
これで、nameカラムが"_"のものだけがヒットします。
追記(上で色々書いたけど以下がbetter!)
コメントでもご指摘いただいたのですが、
今回の要件である、
Brandテーブルのnameカラムが"_"のものだけ、"ユニクロ"に変更したい
を実装するには、以下のようなコードがシンプルかつ安全であると思います。
Brand.where(name: "_").update_all(name: "ユニクロ")