こんにちは、WEBエンジニアのChoi(チェ)です。 BUYMAの購入者向け機能を開発するチームで、主にSEO改善の業務を担当しています。
この記事はEnigmo Advent Calendar 2025の23日目の記事です。
Railsを使用する際は一般的にMySQLやPostgreSQLが使われますが、BUYMAでは用途に応じてSQL Serverも使用しています。
最初は「どのSQLも大差ないだろう」と思っていましたが、運用を開始するとRails + SQL Server特有のトラブルに遭遇しました。
今回はその中でも、
エラーは一切出ないのに、結果だけが返ってこない
という、かなり気づきにくかったケースをご紹介します。
boolean処理をめぐる誤解
ある APIで、次のようにリクエストパラメータを条件に使っていました。
User.where(active: params[:active])
エラーは発生せず、一見すると問題なさそうに見えました。
しかし実際には、エラーは発生しないものの、条件に一致するデータがまったく返ってこないという現象が起きていました。
SQLログを確認すると、発行されていたのは次のようなSQLです。
WHERE active = 'true'
この時点ではまだ、
「文字列になっているのが問題なんだ」
という程度の認識でした。
しかし「文字列になっていたら、trueに暗黙的に変換されるのではないのか?」という疑問も浮かびました。
RubyとSQLの違い
Rubyでは、次のようなコードが成立します。
if 'false' # 実行される end
Rubyの条件分岐では、falseとnil以外はすべてtruthyとして扱われるため、'false'という文字列も「真」として評価されます。
しかしこれは Rubyレベルでの話です。
ActiveRecordが生成するSQLでは、値は型変換されることなく、そのままバインドされます。
テーブル定義を見て、ようやく原因に気づく
改めてテーブル定義を確認してみると、activeカラムはbooleanではありませんでした。
- カラム型:CHAR(1)
- 想定値:'1'(有効) / '0'(無効)
つまりこのコードは、
HTTP パラメータとして受け取った 文字列をそのままSQLの条件に渡していた
という状態だったのです。
SQL Server側では、'true'はbooleanとして解釈されません。
あくまで 文字列同士の比較として評価されます。
その結果、
エラーは出ない
条件にも一致しない
常に0件が返る
という、分かりづらい不具合になっていました。
MySQLやPostgreSQLであれば、どうなっていたか
ここで気になったのが、 「もしMySQLやPostgreSQLだったら、同じ問題は起きていたのか?」 という点でした。
PostgreSQLの場合
PostgreSQLには明確なboolean型があります。
WHERE active = 'true'
のような条件でも、'true'をbooleanのtrueとして解釈します。
そのため、今回のケースでは 意図した通りにデータが返ってきていた可能性が高いです。
結果として、問題に気づかないまま運用が続いていたかもしれません。
MySQLの場合
MySQLでは、booleanは実体としてはTINYINT(1)です。
'true'や'false'といった文字列は、暗黙的に数値へ変換され、結果が返ることもあります。
ただしこの挙動は、明確な仕様というより暗黙の型変換に依存したものです。
なぜ SQL Server環境で表面化されたのか
この問題自体は、SQL Server固有の文法エラーではありません。
しかし、SQL Serverを採用しているサービスでは
- レガシーなテーブルでは、有効/無効フラグを
CHAR型で管理しているケースが今も存在する
という背景から、Rails + SQL Serverの組み合わせで特に踏みやすい落とし穴だと感じました。
この経験から学んだこと
このトラブルをきっかけに、次の点を強く意識するようになりました。
- DBのカラム型は「現在のRails の常識」と一致するとは限らない
- パラメータをそのまま条件に渡さず、ドメイン上の値('1' / '0' など)に変換してから使う
- 結果が返らない場合は、生成されたSQLを必ず確認する
Rails側で正しく書けていても、DB側の前提が異なるだけで、意図しない挙動にハマることがあると学びました。
明日の記事の担当はWebエンジニアのレミーさんです。お楽しみに。