enumっぽいこと

ActiveRecordenum型ってサポートされてないのかなーと色々調べたけど、どうやら未実装みたい。validates_inclusion_ofによるチェックは可能だけど、そこでの定義とform_tagでのselectタグとをどうやって同期取るんだ、みたいなことになってしまう。

で、enumerations_mixinというプラグインを発見。これを使って、大体目的は達成できた。

テーブル定義

自分はGenericEnumというモデルをmigrateで定義した。

    create_table :generic_enums, :force => true do |t|
      t.column :name, :string
      t.column :category, :string
      t.column :position, :integer, :default => 1
    end

クラス定義

Enumごとにクラスを増やしてしまうと部屋が散らかるので、virtual_enumerationsってのを使う。config/virtual_enumerations.rbを編集すればよい。こんな感じ。

ActiveRecord::VirtualEnumerations.define do |config|
  config.define 'OccupationCategory',
                :table_name => 'generic_enums',
                :conditions => ['category = ?', "occupation_category"],
                :order => 'position ASC'
end

データを作るにはMySQLを直接操作しても良いけど、やっぱりmigrateを使うのが便利。ただし、enumeration_model_updates_permittedをtrueにしてやらないと値の挿入や変更はできない(みたい)。そうしないと処理中にenumの値が変わるというヘンテコな状態になるからでしょ。

    GenericEnum.enumeration_model_updates_permitted = true

    GenericEnum.create(
      :name => 'CEO/CIO',
      :category => 'occupation_category',
      :position => 1
    )

    GenericEnum.create(
      :name => 'VP',
      :category => 'occupation_category',
      :position => 2
    )

enumを使う

あとは他のモデルからこのenumを自由に使える。

class Customer < ActiveRecord::Base
  has_enumerated  :occupation,
                  :class_name => 'OccupationCategory',
                  :foreign_key => 'occupation_id'
end

もちろん、この場合のcusomersテーブルにはoccupation_idを用意しておく必要がある。そして

  customer.occupation = Occupation['CEO/CIO']

みたいに使える。

formから使う

コントローラで

  @occupations = Occupation.all.collect {|p|  [p.name, "#{p.id}"]}

と用意しておいて、フォームで

<%= select('customer', 'occupation_id', @occupations) %>

みたいにすれば、select要素を簡単に作れる。

明日はset型の報告。