enumを数字として取り出したいときがあるかもしれません。
google検索すると、before_type_cast
を使えば良いという記事がたくさん見つかりますが、うまくいかない場合がありました。
その理由と解決策を書いておきます。
before_type_castを使った例
例)Projectモデル:
enum status: { close: 0, open: 1 }
環境は、Rails6 × MySQL
Projectテーブルのstatusを数字として抽出したいと思い、before_type_castを使ってみると・・・
>> @project = Project.first => #<Project id: 1, status: "open", name: "project1", created_at: "2021-12-26 19:02:02.070539000 +0900", updated_at: "2021-12-26 19:02:02.070539000 +0900"> >> @project.status => "open" >> @project.status_before_type_cast => "open" >> @project.read_attribute_before_type_cast(:status) => "open"
あれれ?どうして_before_type_cast
でうまくいかないのでしょうか・・・
シンボルで代入するとシンボルで、文字列として代入すると文字列で返ってくるようです。
そもそも、enumは、DBに保存される時点でenumの何かしらの処理が走って数値に変換されて保存されている(のであろう)ということですね。とりあえず雰囲気ですが、
- DBでは、enumはinteger型。なので、saveやupdateなどによってしっかりDBに保存された場合は、しっかり数値を返す。
- newや=で単に代入しただけとか、バリデーションを走らせただけとかで値がDBに完全に保存されていない場合は、代入した生の値をそのまま返す。
そんなメソッドが _before_type_cast
、みたいな理解でとりあえず良さそうです!(ソースコード)
では、どうすればよいのか?
結論:hashを渡すメソッドから取り出せばOK!
「モデル名.enumのカラム名の複数形」でハッシュが返ってくるメソッドを利用します。詳しくはこちら参照してください。
つまり
>> Project.statuses
=> { close: 0, open: 1}
が返ってくるので、
>> Project.statuses[@project.status] => 1
のように書いてあげれば、確実に数値として取り出せます。
>> @project.class.statuses[@project.status] => 1
でもOK!
@project.statusのところに、例えば代わりにparams[:project][:status]を入れて処理できたりするので、こっちの方が使い勝手は良さそうですね。
参考文献
ActiveRecord::Enumのbefore_type_castは必ず数値を返すわけじゃない – Qiita
エラーの解決手順はこちら
はるすと
最後まで読んでくださってありがとうございました!
コメント