【Rails】enumとは？userに管理権限の例で解説

## enumとは
``integer型``や``string型``の1つであり、``「enum型」``に該当する。
``enum``とは、１つのカラムに指定した複数個の定数を保存できる様にする為のものである。
文字列と値を関係づけてプログラムの可読性を上げるとともに、データベースに格納される値が規定の範囲を超えることがないようにすることができる。

例えば、0が「応答待ち」、1が「リクエスト中」、2が「処理中」、3が「入力待ち」と設定して、 状態を保持する``変数status``があったとする。

これをプログラム上で数値だけを扱っていると、**「どの数値が何を表しているのか」が分からなく**なってくる。そのため、定数定義するなどして、数値に名前を付けて可読性を上げるのために使われる。

``「enum型」``ではその定義の中で名前を羅列すると、それらの名前に自動で値を割り当ててくれる。

大まかな特徴は以下の３つ。
``・名前（文字列）のリストに一意の値が割り当てられる``

``・定義の順番通りに値が割り当てられ、追加や削除すると自動的に割り当て直される（値を指定することも可能）``

``・enum型の変数は、定義されている以外の値を受け付けない（例外が発生する）``

## enumの使い方
``Railsのenum```は、**モデルに定義することができる**型で、定義することで、データベースの特定のカラムの値（整数値）を、指定した文字列（シンボル）で扱うことができる。

まず``enum``を使うために

1.テーブルにenum用のカラムを用意する
2.モデルにenumの定義をする必要がある。

``user``に管理権限の有無を例に、
``roleカラム``にて、``0``であれば一般ユーザー・``1``であれば管理者ユーザーとして権限を与える例でやっていく。

### 1.テーブルにenum用のカラムを用意する
まずは``userテーブル``に``roleカラム``を追加する際には型を、``Integer型``か``boolean型``の２択になる。

**``◆integer型``**
2個以上の定数を紐付けたい場合は型はinteger型で定義。

**``◆boolean型``**
2個の定数を紐付けたい場合**かつ**``真偽値を保存したい``時はboolean型で定義。
（``enum``を設定しなくても``boolean型``だけで充分機能は実装できるので``enum``を設定する必要は特にないので、基本的には``integer型``で良さそう）

今回は``integer型``での実装例として扱う。

```add_role_to_users.rb
class AddRoleToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :role, :integer, default: 0, null: false
  end
end
```

空白データは存在しない前提なので、``null: false``にし``default: 0(初期値には0)``を指定する。

### 2.モデルにenumの定義
```user.rb
class User < ApplicationRecord
  #hashで定義する場合
  enum role: { general: 0, admin: 1 }

  # シンボル配列で定義する場合
  enum role: [ :general, :admin]

  # 文字配列で定義する場合
  enum role: [ "general", "admin"]

end
```

基本的にどの方法で定義しても可能。特に大きな違いはないが、しいて挙げるならば下記の２つが違いになる。

``・hashの定数と整数の紐付けは0から始めなくても良い``
``・配列で定義する方がインデックスが自動で定数と紐づいてくれるので、記述量が少なくすっきりしたコードになる``

**◆enumを定義する上での注意点**
``enumのカラム``を設定するときに気をつけないといけないことは、カラムに**予約語を設定**すること。

予約語とは、言語側(今回で言うと``ruby``)で既にこの単語は言語(``ruby``)で使用しているから使わないで、という単語のこと。
例えば``ruby``では``nil``とは何もないという意味がある。これを変数で定義すると

```nilを変数として定義した場合.
nil = '何もない'
SyntaxError: (irb):1: Can't assign to nil
```
上記の様に、``nil``は既に``ruby側``で定義しているので変数として定義できないというエラーが出る。
これはつまり、``ruby側``で``nil``という単語は何もないという意味で既に予約している(定義している)ので、変数としては使わないで、ということになる。この様に言語側で既に使うと予約してる単語を予約語と言う。

``enum``は複数の定数を登録するので、カラム名を``ActiveRecord``で使用している予約語の``type``にしてしまいがちなので、予約語はカラム名として使えないためエラーになるので注意。

## enumの便利なメソッド
``・確認メソッド``
今enumカラムに入っている定数が何なのか確認するメソッドのこと。

```確認メソッド.
#あるuserが管理権限を持っているかどうか確認するとき
user.general?
=> false

user.admin?
=> true

user.test?
NoMethodError: undefined method `test?'
```
確認メソッドは上記の様に使用する。

モデルのインスタンスに対して``インスタンス.定数名?``の形でenumカラムに指定した定数が入っていれば``true``が返ってきて、指定した定数が入っていなければ``false``が返ってくる。

そして登録していない定数である``user.test?``に関しては、エラーが出る。

``・更新メソッド``
更新メソッドとは、enumカラムに入ってある定数を別の定数に更新するメソッドのこと。
モデルのインスタンスに対して``インスタンス.定数名!``の形で使う。

```更新メソッド.
あるuserに管理権限を付与するとき
user.role
=> "general"

user.admin!
UPDATE `users` SET `role` = 1,..省略
=>true
```

``・定数リスト取得メソッド``
定数リスト取得メソッドとは、モデルファイルの``enum``に記載している複数個の定数リストを取得するメソッドのこと。
``モデルクラス.enumカラム名の複数形``という形で使用。

```定数リスト取得メソッド.
User.roles
=> {"general"=>0, "admin"=>1}
```

## enumの日本語対応
Railsには、``enum``をi18n対応させる``gem「enum_help」``が用意されているので、簡単に行うことができる。

**手順**
1.enum_helpのインストール 
2.localeファイルの作成 

**1.enum_helpのインストール**
Gemfileに``gem 'enum_help'``と記載後、``bundle install``を実施。

**2.localeファイルの作成**
``config/locales/activerecord/ja.ymlファイル``を作成し、翻訳を記載。

```ja.yml
ja:
  activerecord:
  enums:
   user:
    role:
     general: 一般ユーザー
     admin: 管理者
```

``user``に対して``role_i18n``インスタンスメソッドを使うと、日本語化出来たかどうか確認ができる。

```ターミナル.
irb(main):001:0> User.roles_i18n
=> {"general"=>"一般", "admin"=>"管理者"}
```

## 参考記事
[【Rails入門説明書】enumについて解説](https://web-camp.io/magazine/archives/16862)
[【Rails】 enumチュートリアル](https://pikawaka.com/rails/enum)