業務でEnumerizeを使って複数選択可能なカラムを実装する必要があったんですが、パッとやり方がわからなかったので、備忘録としてまとめます。
最後まで読めばEnumerizeで複数選択できるカラムを実装する方法や、その際の注意点を理解できるかなと思います。
Enumerizeとは
EnumerizeはRailsのActiveRecordでenumを使えるようにするためのgemです。
Enumerizeを導入するとデフォルト値やバリデーション、複数選択やスコープ・I18n対応などenumよりも豊富なオプションを提供してくれます。
今回の場合、enumを用いて複数選択できるカラムを実装したかったため、Enumerizeを利用しています。
Enumerizeで複数選択可能なカラムを作る手順
ここではオンラインストアで商品を管理するシステムを例にします。
各商品に複数のタグを割り当てると仮定し、Productモデルにtagsカラムを実装します。
①マイグレーションファイルの作成
まずはマイグレーションファイルを作成します。
対象のカラムに array: true
を設定する方法もあるみたいですが、ここでは公式ドキュメントを参考にタグのデータをシリアライズされた形式で管理することにします。
class CreateProducts < ActiveRecord::Migration[6.1]
def change
create_table :products do |t|
t.string :name
t.text :tags # タグのデータをシリアライズされた形式で保存する
t.timestamps
end
end
end
②モデルファイルの設定
マイグレーションが完了したら、次はモデルファイルにEnumerizeの設定を記述します。
以下のようにモデル内でserialize
を指定し、multiple: true
を付与する必要があります。
class Product < ApplicationRecord
extend Enumerize
serialize :tags, Array
enumerize :tags, in: [:book, :clothing, :food, :electronics], multiple: true
end
これで複数選択可能な列挙型カラムが実装できました。
なおEnumerizeはデフォルトでinclusionバリデーションをかけてくれるので、わざわざ書く必要はありません。
列挙型カラムの注意点
1つのカラムに複数の値を格納するのはSQLアンチパターンの「ジェイウォーク」に該当します。
なのでEnumerizeに限らず、できれば正規化して複数選択できるカラムの実装を避けた方が賢明です。
上記の例だと、tagsカラムではなくTagモデルを別途作成し、中間テーブルによってProductモデルと関連づけるのが教科書どおりのやり方です。
ぼくの現場では、以下の理由により原則から外れていると認識しつつも実装することとなりました。
- 検索・集計のニーズが低い(インデックスもなし)
- データの更新がめったに発生しない
- 複雑なクエリ操作を行わない
- 管理画面なのでパフォーマンスの懸念が小さい
まとめ
今回の内容から以下の学びが得られました。
- Enumerizeで複数選択できるカラムを作るには、モデルファイル内に
serialize
とmultiple: true
を記述すればよい - ただし、そもそもSQLのアンチパターンに該当するので、原則的には避けるべき
- 原則は認識しつつも、実情に応じた逸脱はかならずしも「悪」ではない
コメント