enumは、DBにはint型(数字)で保存でき、CRUDは人間の言葉で操作できる、大変便利な仕組みですよね。
しかし、数字/英語/日本語の3つの表現があるために思うようにいかないときもあるのでは?
特に、初学者が最初に躓くのがenumをform_withでf.selectさせる時ですよね!
基本を知らないと難しいですが、基本を押さえればそれほど難しいことではないことが最近わかったので、それぞれの対応を整理しておきます。
enumを設定する(前提条件)
Rails6 × MySQL
db/schema.rb:カラムの型はinteger(DBには整数で格納される)
create_table "articles" do |t|
t.integer "status", null: false, default: 0
# (中略)
end
app/models/article.rb:モデルを設定
class Article < ApplicationRecord # (中略) enum status: { close: 0, open: 1 } end
数字→英語だけなら以上の設定のみでもOK。日本語も導入する場合は下記の設定も行う。
Gemfile:日本語化のためのgemを導入
gem 'rails-i18n'
gem 'enum_help'
config/application.rb:日本語化しておく
module SampleApp
class Application < Rails::Application
# (中略)
config.i18n.default_locale = :ja
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
end
end
config/locales/ja.yml:localesで日本語を設定
ja:
enums:
article:
status:
close: '非公開'
open: '公開'
本記事は、上記のように、enumの設定×日本語化の設定が済んでいる状態を前提に書いていきます。
locales配下をディレクトリで分けたり、ja.ymlではなくファイル名を変えることはあると思いますが、それでも以下のメソッドは変わらず使えます。
bundle installやサーバーの立ち上げ直しも忘れずに。
enumを変換する(これを押さえれば応用が効く!)
英語↔数字
class Article(Articleモデル)で定義したハッシュをそのまま使います。
英語→数字
「モデル名.enumのカラム名の複数形」でハッシュが返ってきます。
>> Article.statuses
=> { close: 0, open: 1}
したがって、下記のようにすれば変換できます。
>> Article.statuses["open"]
=> 1
数字→英語
これはあまり使わないかもしれませんが、invertメソッドを使って英語→数字の逆を利用します。
>> Article.statuses
=> { close: 0, open: 1}
>> Article.statuses.invert
=> { 0: close, 1: open}
したがって、下記のようにすれば変換できます。
>> Article.statuses.invert[1]
=> "open"
英語↔日本語
_i18nを使います。
英語→日本語
「モデル名.enumのカラム名の複数形_i18n」でハッシュが返ってきます。
>> Article.statuses_i18n
=> {"close"=>"非公開", "open"=>"公開"}
したがって、下記のようにすれば変換できます。
>> Article.statuses_i18n["open"]
=> "公開"
日本語→英語
先ほどと同様に、invertメソッドを使って英語→日本語の逆を利用します。
>> Article.statuses_i18n
=> {"close"=>"非公開", "open"=>"公開"}
>> Article.statuses_i18n.invert
=> {"非公開"=>"close", "公開"=>"open"}
したがって、下記のようにすれば変換できます。
>> Article.statuses_i18n.invert["公開"]
=> "open"
enumを表示する
説明の便宜上、インスタンス変数を使っていきます。
@article = Article.first
1.英語で表示
文字列で表示するだけなら、普通に
>> @article.status
=> "open"
でOKです。文字列ではなくシンボルがほしいなら、
>> @article.status.to_sym
=> :open
としてあげれば良いですね。
配列がほしい場合は、keysを使ってあげれば良いですね。
>> Article.statuses
=> { close: 0, open: 1}
>> Article.statuses.keys
=> ["close", "open"]
配列すらシンボルでほしいシチュエーションがあるとしたならこちら↓
>> Article.statuses.keys.map(&:to_sym)
=> [:close, :open]
2.日本語で表示
日本語化が済んでいれば、
>> @article.status_i18n
=> "公開"
でOKです。ビューではこれを一番使うのかなと思います。
配列が欲しい場合はあまりないかもしれませんが、valuesを使ってあげれば、出せます。
>> Article.statuses_i18n
=> {"close"=>"非公開", "open"=>"公開"}
>> Article.statuses_i18n.values
=> ["非公開", "公開"]
3.数字で表示
これがやっかいです。上記の「enumを変換する」を使って、
>> Article.statuses => { close: 0, open: 1} >> Article.statuses[@article.status] => 1
のように書いてあげる必要があります。
before_type_castを使う方法もあるのですが、うまくいくときとそうでないときがあります。気になる方は下記読んでみてください。
こちらも、配列がほしい場合はあまりないかもしれませんが、valuesを使ってあげれば良いですね。
>> Article.statuses
=> { close: 0, open: 1}
>> Article.statuses.values
=> [0, 1]
enumをform_withで利用する
フォームでenumを選ばせる場合、ラジオボタンかセレクトボックスにする場合が多いのではないでしょうか。
その際、表示は日本語にしたいけど、コントローラにsubmitするデータとしては数字か英語で渡したい場合がほとんどだと思います。なお、今回のような設定だと、数字↔日本語の設定はしていないので、渡すデータは英語に限られます。
したがって、セレクトボックスに関して言えば、日本語→英語の変換を利用すれば良いわけですね。例えばこんな感じで。
= f.select :status, options_for_select(Article.statuses_i18n.invert), {include_blank: "選択してください"}, { class: "form-control"}
enumまとめ
enumの操作、という観点でまとめてみました。設定済の
- 英語↔数字
- 英語↔日本語
の変換(ハッシュの扱い)を覚えてしまえば、あとはいくらでも応用が効くと思うので、この記事がenumに悩まされるエンジニアやプログラミング学習者に届くと良いなと思います。
最後まで読んでくださってありがとうございました!
画像提供:Anja🤗#helpinghands #solidarity#stays healthy🙏によるPixabayからの画像
コメント