Ruby
Rails
リファクタリング
I18n
enum

i18n、enumを利用して、formforのf.selectを日本語化する

実装したかったこと enumとf.selectの併用

一度作った機能をリファクタリングしているのですが、プルダウンで項目を選んでpostするという動作の中で
中身が気持ち悪いところがあったので修正。モデルはbookです。

schema.rb
t.category "string"
new.html.erb
<%= f.select :category, [["男向け", "男向け"], ["女向け", "女向け"], ["その他", "その他"]] %>

スクリーンショット 2018-07-16 19.16.55.gif

当初はこんな感じで書いていたのですが、これだとデータベースに文字列のデータが直接入るため、あまりよろしくありません。
なので、enumを利用して、データベースには数値が入るようにしました。
categoryはもちろんinteger型にします。

必要な技術

ここからは実装に必要な技術を羅列します。

enum

有名なenumですね。
カラムの中の項目に整数を割り当てて、メソッドを簡単に実行できるようになったり、可読性をあげることができるようになったりします。
この記事参考にしてました。

【Rails入門】enumの使い方まとめ

今回はenumを

book.rb
enum category:{for_men: 0, for_women: 1, for_others: 2}

こんな感じでセットします。

あと、enumを簡単に日本語化できるように、お助けのgemを入れます。
enum_helpというgemです。

ruby.rb
#gemfile

gem 'enum_help'

bundleしましょう。

YAML

次に、yamlですね。
yamlは階層化されたデータを書きやすくしてくれる表記方法です。

参考記事: YAMLとは何か? - いつもRailsの設定ファイルで出てくるやつの正体

rails5においては、config/locales以下にja.ymlというファイルを作成します。
このja.ymlファイルの中にこの英語表記は日本語ではこう表すんだよということを教えてあげます。
具体的には下のように書きます。

ja.yml
ja:
  activerecord:
   #(この辺に他の設定値がある)
  enums:
    book:
      category:
        for_men: 男向け
        for_women: 女向け
        for_others: その他

f.select

これは一番最初に書いてありますが、railsが用意してくれているform_forの中で、プルダウンで項目を選ぶことができるようになります。

【開発メモ】Ruby on Railsのform_forでドロップダウンリストの選択ボックスを設置する方法
こちらの記事を毎回参考にしています。

ruby.html.erb
<%= f.select カラム名, [["表示する文字”, "データベースに登録する値”], ["表示する文字”, "データベースに登録する値”]] %>

最終コード

最後にどのようなコードを書けば実装できたのかも書いておきます。

new.html.erb
<%= f.select :category, Book.categories.keys.map {|k| [I18n.t("enums.book.category.#{k}"), k]} %>

まず,Book.categoriesで
{"for_men"=>0, "for_women"=>1, "for_others"=>2 }というハッシュが取れます。
keysでそのうちのキーの部分(ハッシュの左側)を配列で取り出し、mapより左の中にあるkに入れていきます。
その次にあるI18n.tですが、これはja.ymlの表記の通りに翻訳してくれるというメソッドです。
tのあとの()内でどの階層にあるものかということを明記しています。

(ここ結構ハマったところで、しっかり階層を明記してあげないとダメです!)
今回ではenumの下にある、bookの下にある、categoryの下にあるfor_menを訳せという命令になります。
もちろん繰り返すので,for_womenとfor_othersも訳されていきます。

I18n.tの左横とkの右横に[]がありますが、これがf.selectの[]の部分ですね。

もう一つ大事なことがあって、データベースには数値が数値が入りますが、postするパラメータはBook.categoriesのキーの部分です。
検証で見てみると早いのですが、formはこうなります。

スクリーンショット 2018-07-16 20.53.46.gif

valueは数値じゃないんかい!と思うのですが、このような仕様だそうです。
最初ここを0とかにしたら、'0'is not a valid categoryとか言われてエラーになりました。

色々罠が張り巡らされている実装ですが、お役に立てれば幸いです。