[Rails]ユーザー情報にenumを使った実装

# はじめに
初めまして、Railsを勉強中のものです。
現在SNSアプリを開発中です。

よくある投稿機能や出品機能などに持たせるカラムとして、あらかじめ用意した値の中から選択させる属性を扱う場合`enum`が便利だと色んな記事で見てたのですが、
思っていたよりすんなり実装できなかったので初めて`enum`を使う方の参考になればと思い記録しておきます。

あくまで私が実装した内容を載せるだけなので、細かい説明は参考にしたリンクを貼っておきますのでそちらをご参照ください。

## 実装する内容
ユーザー情報に持たせるカラムとして、性別と年齢を`enum`を使って実装していきます。
Railsのバージョンは`5.2.4`です。今回は`haml`で書いてます。

それではやってみましょう。
# enumで値を定義する

まずはマイグレーションファイルから。
`enum`を使うカラムは`integer`型で用意します。

```ruby:db/migrate/xxxx_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
     
      t.string :nickname,            null: false
      t.string :email,               null: false, default: ""
      t.string :encrypted_password,  null: false, default: ""
      t.string :profile,             null: false
      # 型はintegerにする
      t.integer :gender,             default: 0
      t.integer :age,                default: 0
      
      # .省略
  end
end

```

初めオプションは`null :false`にしてました。今回はそれでも問題はなかったのですが、他の記事を見るとどれも`default: 0`で設定してたのと、公式ではこちらが推奨されてるみたいなので直しました。

次にモデルで実際にデータを用意します。

```ruby:app/models/user.rb
class User < ApplicationRecord
  enum gender: { gender_private: 0, male: 1, female: 2, others: 3 }
  enum age: { age_private: 0, teens: 1, twenties: 2, thirties: 3, forties: 4, fifties: 5, over_sixties: 6 }
end
```

配列で定義してる方もいました。

```ruby:app/models/user.rb
class User < ApplicationRecord
  enum gender: [ :gender_private, :male, :female, :others ]
  enum age: [ :age_private, :teens, :twenties, :thirties, :forties, :fifties, :over_sixties ]
end
```

どちらでも大丈夫ですが、配列の場合対応する数字が自動で0から順になるということだけ注意が必要です。
他のカラムと区別したり、わかりやすくするために1、10、20などの数字にする方もいるみたいです。その場合はハッシュで書くしかないですね。

# viewでフォームを実装する


次にフォームの実装です。
私はセレクトボックス で用意しました。


```ruby:app/views/devise/registrations/new.html.haml
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
  
  .field
    = f.label :gender
    %br/
    = f.select :gender, options_for_select_from_enum(User, :gender)
  .field
    = f.label :age
    %br/
    = f.select :age, options_for_select_from_enum(User, :age)
```

フォームの実装はいろいろな書き方があると思いますが、私の場合
`ArgumentError ('2' is not a valid gender):`
というエラーが出てしまい、色々試した結果最終的に上の書き方になりました。
同じエラーに当たった方は、こちらの記事が詳しく書いてありました。

[enumを使うとArgumentError in TasksController#create => '2' is not a valid status_id](https://qiita.com/e-yoshida/items/fa4d300786fbedf9845d "Qiita")


これで`enum`を使って性別と年齢を登録できるようになりましたが、現状セレクトボックスに表示されるのは英語のままになっています（age_private、teens、twenties ...）


# プルダウンの表示を日本語化する
こちらもいくつかやり方があるみたいです。
gemを使う方法もあるみたいですが今回は別の方法で実装します。

[【Rails】Enumってどんな子？使えるの？](https://qiita.com/ozackiee/items/17b91e26fad58e147f2e#%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%8C%96%E3%82%92%E9%A7%86%E4%BD%BF%E3%81%97%E3%81%A6view%E8%A1%A8%E7%A4%BA)

こちらの記事を参考にさせてもらいました。
というかまんまこの通りやりました。


ちなみにgemを使う方法はこちらに書いてあります。
[【初心者向け】i18nを利用して、enumのf.selectオプションを日本語化する[Rails]](https://qiita.com/tanutanu/items/d44a92425188a4489ec6)


## ja.ymlファイルの作成

まず、i18機能で日本語設定をしていない場合はファイルを用意する必要があります。



```ruby:Gemfile
#rails5系
gem 'rails-i18n', '~> 5.1'

#rails4系
gem 'rails-i18n', '~> 4.0' 
```

こちらのgemを導入、もしくは

[svenfuchs/rails-i18n](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml)
こちらのファイルをコピーして、`config/locales/ja.yml`ファイルを作ります。

そのファイルに`enum`で定義した値を日本語に変換させるのための記述をします。

```ruby:config/locales/ya.yml
:ja
  #省略
  enums:
    user:
      gender:
        gender_private: "非公開"
        male: "男性"
        female: "女性"
        others: "他"
        #省略
```
## デフォルトの言語を日本語化

次に`application.rb`でデフォルトの言語を日本語化するための設定です。

```ruby:config/application.rb
module SnsApp
  class Application < Rails::Application
    #省略
    
    #追記
    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]

   #省略
  end
end
```

これで先程の`ja.yml`ファイルが読み込まれます。

そしてもう一つファイルを作ります。

##Helperメソッドを用意する

`app/helpers`の下にファイルを作ります。

```ruby:app/helpers/enum_helper.rb
module EnumHelper
  # クラスオブジェクトとカラム名を引数として呼ばれるコールバック関数です
  def options_for_select_from_enum(klass,column)
    #該当クラスのEnum型リストをハッシュで取得
    enum_list = klass.send(column.to_s.pluralize)
    #Enum型のハッシュリストに対して、nameと日本語化文字列の配列を取得（valueは使わないため_)
    enum_list.map do | name , _value |
      # selectで使うための組み合わせ順は[ 表示値, value値 ]のため以下の通り設定
      [ t("enums.#{klass.to_s.downcase}.#{column}.#{name}") , name ]
    end
  end
end
```

上の記事から丸ごと頂きました。

これでプルダウンの日本語も完了です！

#最後に

今回はenumを使った実装方法を書きましたが、他に都道府県のカラムも欲しかったのでそちらは`active_hash`で実装しました。

使い勝手も実装のしやすさも`active_hash`の方が楽なのですが、性別など２個か３個しかない値のためにモデルをいっぱい作るのも無駄なような感じがしたのと、
大体皆さん性別は`enum`で実装してる方が多いみたいなので今回使ってみました。
実際覚えてしまえば使う場面はいっぱいあると思うので、必要に応じて積極的に使っていこうと思います。

私が書いたやり方でうまくいかなかった方は、今回参考にした記事をまとめておきますので色々見て見てください！

また、無駄な記述や間違った認識などがありましたらご指摘いただけるとありがたいです！

#参考にした記事


[【Rails】Enumってどんな子？使えるの？](https://qiita.com/ozackiee/items/17b91e26fad58e147f2e#%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%8C%96%E3%82%92%E9%A7%86%E4%BD%BF%E3%81%97%E3%81%A6view%E8%A1%A8%E7%A4%BA)

[Ruby on Rails:ModelのプロパティにEnumを使う※おまけ：ラジオボタンでEnumを扱う](https://madogiwa0124.hatenablog.com/entry/2017/12/24/222156)

[enumを使うとArgumentError in TasksController#create => '2' is not a valid status_id](https://qiita.com/e-yoshida/items/fa4d300786fbedf9845d "Qiita")

[【初心者向け】i18nを利用して、enumのf.selectオプションを日本語化する[Rails]](https://qiita.com/tanutanu/items/d44a92425188a4489ec6)

[[初学者]Railsのi18nによる日本語化対応]
(https://qiita.com/shimadama/items/7e5c3d75c9a9f51abdd5)