🚂
Rails enumの integer vs string:どちらを選ぶべき?
はじめに
Rails の enum でステータス管理をする際、integer型とstring型のどちらを選ぶべきか悩んだことはありませんか?
# integer型
enum :status, { published: 0, pending: 1, ban: 2 }
# string型
enum :status, %i[published pending ban]
この記事では、それぞれのメリット・デメリットを比較し、プロジェクトに最適な選択ができるようにまとめました。
Rails バージョンによる違い
Rails 7.0 以前
-
enumは基本的に integer型が前提 - string型を使う場合は、少し工夫が必要でした
# Rails 7.0以前でstring型を使う場合
enum status: {
published: "published",
pending: "pending",
ban: "ban"
}
Rails 7.1 以降
- string-backed enum が正式サポート
- より簡潔な記法で string型 enum を定義可能
# Rails 7.1以降の新しい記法
enum :status, %i[published pending ban], prefix: true
パターン① Integer型 enum
実装例
# model
class Post < ApplicationRecord
enum :status, { published: 0, pending: 1, ban: 2 }
end
メリット ✅
1. DB効率が良い
- 整数として保存されるため、データサイズが小さい
- 大量データを扱うときにパフォーマンス面で有利
- インデックスサイズも小さく済む
2. 便利なヘルパーメソッドの自動生成
post.published! # ステータスを変更
post.published? # 判定
Post.published # スコープ
3. 順序の明確な定義
- 並び替えや比較がしやすい
-
Post.statuses.keys.index(post.status)で順序を取得可能
デメリット ❌
1. DBの可読性が低い
- データベースを直接見ると
0, 1, 2といった数値のみ - 何を表しているか直感的に理解できない
2. マッピング変更に弱い
- 例:
published: 0→published: 1に変更すると既存データが壊れる - 新しいステータスを途中に追加するのが困難
パターン② String型 enum
実装例
# Rails 7.1以降
class Post < ApplicationRecord
enum :status, %i[published pending ban], validate: true
end
# データベースには "published", "pending", "ban" として保存される
メリット ✅
1. DBの可読性が高い
- データベースを直接見ても
"published","pending"など、意味が明確 - デバッグやデータ分析が容易
2. 変更に強い
- 後から値を追加・順序を変えても既存データに影響なし
- リファクタリングが安全
3. Rails 8以降の方向性と一致
- 型安全で、ActiveRecord::Enum の今後の推奨パターン
- 可読性重視の現代的なアプローチ
デメリット ❌
1. データサイズがやや大きい
- 文字列として保存するため、integer型より容量を使用
- 数百万件レベルになるとパフォーマンス差が出る可能性
2. インデックスのコスト
- 文字列インデックスは数値インデックスより大きくなる
比較表
| 観点 | Integer enum | String enum |
|---|---|---|
| DBの可読性 | ✗ | ◎ |
| マッピング変更耐性 | ✗ | ◎ |
| パフォーマンス | ◎ | △ |
| データサイズ | ◎ | △ |
| Railsの推奨トレンド | △ | ◎ |
| スコープ/メソッド | ◎ | ◎ |
結論:どちらを選ぶべき?
String型 enum がおすすめなケース 👍
- 小〜中規模アプリケーション
- ステータスが増えたり変更される可能性があるモデル(投稿、予約など)
- チーム開発でDB可読性を重視したい
- 長期的な保守性を優先したい
Integer型 enum を検討すべきケース
- 超大規模データ(数百万件超)
- バッチ更新が頻繁
- パフォーマンスが最優先
- ステータスが固定で変更の可能性が極めて低い
実装のベストプラクティス
String型 enum を使う場合
# migration
class AddStatusToPosts < ActiveRecord::Migration[7.1]
def change
add_column :posts, :status, :string, default: "published", null: false
add_index :posts, :status # 検索性能を考慮
end
end
# model (Rails 7.1以降)
class Post < ApplicationRecord
enum :status, %i[published pending ban],
validate: true, # 不正な値を防ぐ
prefix: true # published_status? のようなプレフィックス付きメソッド
end
まとめ
現代的なRailsアプリケーションでは、String型 enum の採用が増えています。特に Rails 7.1 以降では公式サポートも充実し、可読性と保守性の観点から推奨される選択肢となっています。
ただし、パフォーマンスが最重要課題となる大規模システムでは、Integer型 enum も依然として有効な選択肢です。プロジェクトの特性を見極めて、最適な方を選択しましょう。
一般的な推奨:迷ったら String型 enum を選ぶことをおすすめします。後から Integer型への移行は可能ですが、その逆は既存データの移行が複雑になるためです。
Discussion