enum型または列挙型とは、複数の変数をまとめて管理するためのデータ型のことです。
int型やstring型などに比べるとあまり聞きなれないかもしれませんが、非常に便利な型です。
この型は文字列として扱いたいものをデータベースには数値として保存しておくというものです。

ActiveRecordのEnumを使用することで、データベースの数値型カラムと任意の文字列を紐づけることができます。
Railsに組み込まれたEnum以外にも、enumerizeを利用することでより柔軟な処理ができるようになります。

オンラインでプログラミング学習を始めてみたいなら、米国シリコンバレー発祥の世界最大級のオンライン学習プラットフォーム、Udemyがおすすめです。
こちらの記事で紹介するフレームワーク、Ruby on Railsも学ぶことができます!
よくわかるRuby on Rails入門 オンライン講座

enum型とは

enum型の使いどころは様々ですが、どのような場面で力を発揮するかは例を見てみるとすぐにわかります。

たとえば、データベースのテーブルに性別データを保存するカラムがあったとします。
性別は一般的に「男性」、「女性」、「その他」の3つに大別されます。
これらに対して男性=1、女性=2、その他=3とそれぞれ対応した数値を割り当てておきます。
データベース上では数値として情報を保存し、これらをアプリケーション層で文字列に対応付けすることができれば、数値データを文字列として扱うことができます。

そういった機能をサポートしてくれるのがenum型です。

Ruby on Railsではデフォルトで用意されているActive Recordの機能としてEnumがあります。
また、より柔軟な処理ができるように開発されたenumerizeというサードパーティのパッケージもよく使われます。

enum型を利用することで、コードの柔軟性や保守性が向上するという利点があります。
開発の途中で使用する文字列を変更したくなった場合でも、データベースに保存されているのは数値なので、それまでのデータへの影響が全くありません。
また、設定してある値以外は基本的に保存できないようにするため、予期しないデータが混在することを防げます。

必ず利用しなければいけないというものではありませんが、意外と活用できる機会が多いので身につけておいて損はないでしょう。

ここからはイベント管理アプリを作ってenum型の使い方を紹介していきます。
同じ環境で試してみたい方は、以下に従ってコマンドを実行しておいてください。

# 新規プロジェクトの作成
$ rails new event-app
$ cd event-app

# scaffoldコマンドでEventモデル周りのファイルを自動生成
$ rails generate scaffold event name:string hold_date:date

# データベースの作成
$ rails db:create

# マイグレーションの実行
$ rails db:migrate

Enumの使い方

enum型の設定

まずはイベントに関するデータを扱うEventモデルに対して開催状況を管理するカラム(status)を追加してみます。
マイグレーションファイルを生成しましょう。

$ rails generate migration AddStatusToEvents

マイグレーションファイルを開き、以下のようにカラムを追加することを記述します。
適用したいデータベースのカラムは数値型にしておきます。

class AddStatusToEvents < ActiveRecord::Migration[6.1]
  def change
    add_column :events, :status, :integer, null: false
  end
end

忘れずにマイグレートも実行します。

$ rails db:migrate

カラムが追加できたら、モデル(Active Record)の中に数値と文字列の対応関係を記述します。
名称(シンボル名)と数値の組み合わせは、ハッシュ(連想配列)の形式で定義しておきます。

class Event < ApplicationRecord
  enum status:
  {
    scheduled: 0,
    rehearsal: 1,
    in_sesson: 2,
    archive:   3,
    cancel:    4,
  }
end

レコードの登録

レコードを登録してenum型の挙動を確認してみます。
以下の例では、statusというカラムに対して scheduled という文字列を指定していますが、発行されたSQLを見てみると数値型の0が保存されているのがわかります。
このことからも、Railsのモデル(Active Record)が数値と文字列を対応付ける橋渡しをしてくれていることがわかります。

$ rails console

irb(main):001:0> event = Event.new
   (0.6ms)  SELECT sqlite_version(*)
=> #<Event:0x00000267d7975b58 id: nil, name: nil, hold_date: nil, created_at: nil, updated_at: nil, status: nil>

irb(main):002:0> event.name = 'sample event'
=> "sample event"

irb(main):003:0> event.hold_date = Time.parse('20230101')
=> 2023-01-01 00:00:00 +0900

irb(main):004:0> event.status = 'scheduled'
=> "scheduled"

irb(main):005:0> event.save
  TRANSACTION (0.1ms)  begin transaction
  Event Create (0.8ms)  INSERT INTO "events" ("name", "hold_date", "created_at", "updated_at", "status") VALUES (?, ?, ?, ?, ?)  [["name", "sample event"], ["hold_date", "2023-01-01"], ["created_at", "2021-11-08 23:10:00.978056"], ["updated_at", "2021-11-08 23:10:00.978056"], ["status", 0]]
  TRANSACTION (2.3ms)  commit transaction
=> true

また、enum型のカラムはそもそも数値型と変わらないので、数値を指定してレコードを保存することもできます。

$ rails console

irb(main):001:0> event = Event.new
   (0.9ms)  SELECT sqlite_version(*)
=> #<Event:0x000001ec737ec140 id: nil, name: nil, hold_date: nil, created_at: nil, updated_at: nil, status: nil>

irb(main):002:0> event.name = 'sample event 2'
=> "sample event 2"

irb(main):003:0> event.hold_date = Time.parse('20230501')
=> 2023-05-01 00:00:00 +0900

irb(main):004:0> event.status = 0
=> 0

irb(main):005:0> event.save
  TRANSACTION (0.1ms)  begin transaction
  Event Create (0.9ms)  INSERT INTO "events" ("name", "hold_date", "created_at", "updated_at", "status") VALUES (?, ?, ?, ?, ?)  [["name", "sample event 2"], ["hold_date", "2023-05-01"], ["created_at", "2021-11-08 23:17:45.120039"], ["updated_at", "2021-11-08 23:17:45.120039"], ["status", 0]]
  TRANSACTION (2.9ms)  commit transaction
=> true

enumの参照と更新

先ほど保存したレコードを取得してenum型のカラムを参照すれば、シンボル名(数値に対応した文字列)が確認できます。
さらに、before_type_castでデータベースに保存されている実際の数値を確認することもできます。

$ rails console

irb(main):001:0> event = Event.find(1)
   (0.5ms)  SELECT sqlite_version(*)
  Event Load (0.2ms)  SELECT "events".* FROM "events" WHERE "events"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Event:0x000001d6d9aa1868 id: 1, name: "sample event", hold_date: Sun, 01 Jan 2023, created_at: Mon, 08 Nov 2021 23:10:00.978056000 UTC +00:00, updated_at: Mon, 08 Nov 2021 23:10:00.978056000 UTC +00:00, status: "scheduled">

irb(main):002:0> event.status
=> "scheduled"

irb(main):003:0> event.status_before_type_cast
=> 0

enumのシンボル値に?を付けたメソッドを用いると、状態を確認できます。
enumのシンボル値に!を付けたメソッドを用いると、状態を更新できます。

カラムの内容を簡単に更新できるので、非常に便利ですね。

irb(main):004:0> event.scheduled?
=> true

irb(main):005:0> event.archive?
=> false

irb(main):006:0> event.rehearsal!
  TRANSACTION (0.1ms)  begin transaction
  Event Update (0.9ms)  UPDATE "events" SET "updated_at" = ?, "status" = ? WHERE "events"."id" = ?  [["updated_at", "2021-11-08 23:21:19.812699"], ["status", 1], ["id", 1]]
  TRANSACTION (22.4ms)  commit transaction
=> true

irb(main):007:0> event.scheduled?
=> false

irb(main):008:0> event.rehearsal?
=> true

データベースの確認

enum型のカラムが実際に数値で保存されていることを確認してみましょう。

$ rails dbconsole

SQLite version 3.35.2 2021-03-17 19:07:21
Enter ".help" for usage hints.
sqlite> SELECT name, status FROM events;
sample event|1
sample event 2|0

シンボル値の日本語化

プログラムは基本的にすべてアルファベットで記述し、処理中に日本語を混在させることを防ぎます。
これは、プログラムが文字列を2進数に変換(エンコード)して処理する際のエンコーディング方式などで問題が発生しやすいためです。

そのためenum型のシンボル名を日本語に対応させるには、i18nenum_helpのパッケージを使用します。
ちなみにi18nとは国際化を意味する英単語である「internationalization」を省略したものです。
18はiとnの間に18個のアルファベットがあることを意味しています。

Gemfileに以下のrails-i18nとenum_helpを追加し、パッケージをBundlerでインストールします。

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '3.0.2'

gem 'rails-i18n'
gem 'enum_help'

...
$ bundle install

次にconfig/application.rbの設定を書き換え、使用するロケール(言語)をjaに変更します。

...

module EventApp
  class Application < Rails::Application
    config.load_defaults 6.1
    config.i18n.default_locale = :ja    # この行を追加
  end
end

さらにconfig/localesフォルダの中にja.ymlを作成し、以下のように記述します。
ここではモデル名ごとに指定していますが、代わりにdefaultを使用すればアプリ内全体で値を共有できます。
以下の例でいえば、3行目の event の部分を default に書き換えれば大丈夫です。

ja:
  enums:
    event:
      status:
        scheduled:  '開催予定'
        rehearsal:  'リハーサル中'
        in_session: '開催中'
        archive:    '開催終了'
        cancel:     'キャンセル'

日本語化されたことを確認してみます。
言語ファイル(ja.yml)を適用後の値を取得するには、カラム名_i18n を参照します。

irb(main):001:0> event = Event.find(1)
   (0.9ms)  SELECT sqlite_version(*)
  Event Load (0.3ms)  SELECT "events".* FROM "events" WHERE "events"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<Event:0x0000022cccf24f40 id: 1, name: "sample event", hold_date: Sun, 01 Jan 2023, created_at: Mon, 08 Nov 2021 23:10:00.978056000 UTC +00:00, updated_at: Mon, 08 Nov 2021 23:21:19.812699000 UTC +00:00, status: "rehearsal">

irb(main):002:0> event.status
=> "rehearsal"

irb(main):003:0> event.status_i18n
=> "リハーサル中"

現場を意識した本格的な学習カリキュラムで、本物のスキルを身につけたいならこちら!
困ったときにいつでも相談できるバディ制度でわからないこともすぐに解決できます。
プログラミングスクールといえば【RUNTEQ】

enumerizeの使い方

gemパッケージのインストール

EnumはRailsでデフォルトのenum型を利用するためのものでした。
Gemパッケージのenumerizeは、さらに柔軟に高機能なenum型を利用したい場合によく使われます。

利用するにはまずGemfileにenumerizeを追加し、パッケージをインストールします。

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '3.0.2'

gem 'enumerize'

...
$ bundle install

enum型の設定

enum型の定義の仕方は以下の通りで、Railsのデフォルト機能のEnumとほぼ同じような記述方法となっています。
extendでEnumerizeのモジュールを取り込んでおくのを忘れないようにしましょう。
以下のようにデフォルト値を指定することもできます。

class Event < ApplicationRecord
  extend Enumerize

  enumerize :status, in:
  {
    scheduled: 0,
    rehearsal: 1,
    in_session: 2,
    archive: 3,
    cancel: 4,
  },
  default: :scheduled

enumrizeでシンボル名を日本語化するには、先ほど紹介したconfig/locales/ja.ymlの”enums”の部分を”enumrize”に書き換えます。

ja:
  enumerize:
    event:
      status:
        scheduled:  '開催予定'
        rehearsal:  'リハーサル中'
        in_session: '開催中'
        archive:    '開催終了'
        cancel:     'キャンセル'

enumの参照

enumrizeによるenum型データの参照方法は以下の通りです。

$ rails console

irb(main):001:0> event = Event.find(1)
   (1.1ms)  SELECT sqlite_version(*)
  Event Load (0.2ms)  SELECT "events".* FROM "events" WHERE "events"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=>
#<Event:0x0000019d48bc3608
...

irb(main):002:0> event.status
=> "rehearsal"

irb(main):003:0> event.status_value
=> 1

irb(main):004:0> event.status_text
=> "リハーサル中"

さらに詳しいenumrizeの使い方はこちらです。

まとめ

enum型はデータベースのレコードの状態を表す情報の扱いをサポートしてくれます。
アプリケーション上では文字列として、データベース上では数値として、主に状態を表すときによく用いられます。
まずは基本的なEnumの使い方を身につけ、要件に応じてenumerizeなどのパッケージを利用するようにしましょう!

ひとりではなかなかプログラミングの学習が続かない、未経験だから不安が多い、という方はプログラミングスクールを利用してみるのも有効です。
本物のエンジニアに学ぶことで、時間がない方でも最短でスキルを身につけることができます。
現役エンジニアのパーソナルメンターからマンツーマンで学べる

お悩みの方は、まずは無料キャリアカウンセリングにお申込みください。

関連記事

この記事のタグ