コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

ActiveRecord::Type::Boolean.new.cast はかなり揺らいだ変換になるので気をつける

昔のPHPを彷彿とさせる変換だったので書き留める

環境

$ bin/rails --version
Rails 6.0.3.6

どういうことか

ActiveRecord::Type::Boolean.new.cast は引数をtrueあるいはfalseに変換してくれるのだが、変換の基準は以下のものに引っかかるものがfalseになる。

クラスとしてはこちらに定義がある。

FALSE_VALUES = [
  false, 0,
  "0", :"0",
  "f", :f,
  "F", :F,
  "false", :false,
  "FALSE", :FALSE,
  "off", :off,
  "OFF", :OFF,
].to_set.freeze

また、""nilnil になる

def cast_value(value)
  if value == ""
    nil
  else
    !FALSE_VALUES.include?(value)
  end
end

つまり以下のものはすべて false に変換される

  • false
  • 0
  • "0"
  • :0
  • "false"
  • :false
  • "FALSE"
  • :FALSE
  • "off"
  • :off
  • "OFF"
  • :OFF

また、 以下のものは nil になる

  • nil
  • ""

そしてそれ以外のものは true になる。

false になるシリーズは以下

target = "f"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = 0
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = "false"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = false
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = "FALSE"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = "off"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = :off
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = :false
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = :FALSE
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = 0
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = 1
ActiveRecord::Type::Boolean.new.cast(target)
# => true

ただし False (いわゆるパスカルケース)は設定値にないので true になる

target = :False
ActiveRecord::Type::Boolean.new.cast(target)
# => true

target = "False"
ActiveRecord::Type::Boolean.new.cast(target)
# => true

そして空文字とnilnilになる

target = nil
ActiveRecord::Type::Boolean.new.cast(target)
# => nil

target = ""
ActiveRecord::Type::Boolean.new.cast(target)
# => nil

関連リンク