railsでmysqlのbooleanなカラムをエイリアスで扱う時の注意事

rails+mysqlな環境では、booleanで定義したカラムはtinyint(1)で作られ、中身はtrue/falseではなく、0/1が入る。
そして、railsアプリケーション上でmysqlのtinyint(1)型データを扱う時、値は自動的にtrue/falseとして扱われる。
そこまでは知っていたんだけど、select('foobar_flg as fb_flg')というふうに、カラム名をエイリアスして取り出すと値が0/1なのは知らなかった。

具体的には下記のとおりである。

pry(main)> p = User.select(:foobar_flg)
  User Load (10.5ms)  SELECT  `users`.`foobar_flg` FROM `users`
=> [#<User id: nil, foobar_flg: false>]
pry(main)> p.first.foobar_flg
=> false

pry(main)> p = User.select('foobar_flg as fb_flg')
  User Load (5.8ms)  SELECT  foobar_flg as fb_flg FROM `users`
=> [#<User id: nil>]
pry(main)> p.first.fb_flg
=> 0

ちなみに、selectメソッドの引数に文字列を指定したから0/1が返ってくるというわけではない。
下記のようにエイリアス無しなら、文字列で指定してもtrue/falseに解釈される。

pry(main)> p = User.select('foobar_flg')
  User Load (10.0ms)  SELECT  `users`.`foobar_flg` FROM `users`
=> [#<User id: nil, foobar_flg: false>]
pry(main)> p.first.foobar_flg
=> false

このままだと結構困る。
結論としては、__as使わない__で済むならそれが最善手だと思う。
が、それが無理なら、例えば下記のようにModelのattributeメソッドをoverrideしちゃうのが良さそう。

def fb_flg
  read_attribute(:fb_flg) == 1
end

参考

ruby on rails - Override ActiveRecord attribute methods - Stack Overflow