📌

ActiveRecord で where するときにカラムの型と異なる値を渡すと NULL になる

2024/08/31に公開

NOTE: この記事では Rails 7.1.4 + sqlite3 で動作検証しています。

例えば次のような schema のテーブルに対して

ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.integer :count
    t.boolean :active
    t.timestamps
  end
end

次のように .wherecount に数値以外を渡すとエラーにならずに NULL として扱われます。

pp ActiveRecord::VERSION::STRING
# => "7.1.4"

class User < ActiveRecord::Base
end

puts User.where(count: "hoge").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."count" = NULL

これは内部で "hoge"integer 型 にキャストするときにキャストできず NULL の値として変換されるからになります。
逆に integer 型 にキャストできる場合は文字列の場合でも数値として変換されます。

# "42" は文字列だが 42 としてキャストされる
puts User.where(count: "42").to_sql
# =>< SELECT "users".* FROM "users" WHERE "users"."count" = 42

他にも boolean 型 の場合はそれっぽい値を 0 / 1 として変換します。

puts User.where(active: "true").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active" = 1

puts User.where(active: "false").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active" = 0

puts User.where(active: "42").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active" = 1

puts User.where(active: "hoge").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active" = 1

puts User.where(active: "0").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active" = 0

puts User.where(active: "").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."active" = NULL

ただ、このあたりの型キャストのされ方はもしかしたら使用する RDBMS によって挙動が変わるかもしれません。

GitHubで編集を提案

Discussion