define ActiveRecord constants with DSL.and more!
Ruby
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
lib
spec
.document
.gitignore
.rspec
Gemfile
LICENSE.txt
README.rdoc
Rakefile
VERSION
const_enum.gemspec

README.rdoc

const_enum

ActiveRecordの定数クラス、定数名アクセサ、NamedScope、定数値判定メソッド等を簡単なDSLで作成するためのライブラリ。 ActiveRecord3.xに対応しています。

インストール

Gemfileに以下の行を追加して、bundle installコマンドを実行してください。

gem 'const_enum'

あるいは、以下のコマンドでインストールしてください。

gem install const_enum

設定

定数のラベル定義ファイルを作成

# config/locales/labels_ja.yml
 ja:
   labels:
     user:
       status:
         disable: "無効"
         enable:  "有効"

constメソッドのブロック内で定数を定義

class User < ActiveRecord::Base
  const :STATUS do
    ENABLE    1
    DISABLE   0
  end
end

使用例

定数値へのアクセス

User::STATUS::ENABLE  # 1
User::STATUS::DISABLE # 0

ActiveRecordの拡張

# データを作成
taro   = User.create(:name => 'taro'  , :status => Hoge::STATUS::ENABLE)
hanako = User.create(:name => 'hanako', :status => Hoge::STATUS::DISABLE)

# {ATTR}_labelメソッドが定義される
taro.status_label   # "有効"
hanako.status_label # "無効"

# {ATTR}_{CONST}?メソッドが定義される
taro.status_enable?  # true
taro.status_disable? # false

# was_{ATTR}_{CONST}? ,  #{ATTR}_{CONST}_wasメソッドが定義される
taro.status = User::STATUS::DISABLE
taro.status_enable?      # false
taro.was_status_enable?  # true
taro.status_label_was?   # 有効

# named_scopeが定義される
User.status_enable.all

Validationでの利用

constメソッドで定義される定数クラスはinclude?メソッドを実装しているため、 validates :inclusionで利用することができる。

class User < ActiveRecord::Base
  const :STATUS do
    ENABLE    1
    DISABLE   0
  end
  validates :status, :inclusion => {:in => STATUS}
end

Viewでの利用

constメソッドで定義される定数クラスはEnumerableモジュールをインクルードしているため、 collection_selectにそのまま渡すことができる。 値はvalue、ラベル名labelメソッドを指定する。

user = User.new
form_for user do |f|
  f.collection_select(:status, User::STATUS, :value, :label)
end

定数オブジェクトへのアクセス

Class}::{ATTRで各定数オブジェクトにアクセス可能

User::STATUS[1].class # User::STATUS
User::STATUS[1].value # 1
User::STATUS[1].label # "有効"

ActiveRecord::Base.constメソッドのオプション

prefix: NamedScope、属性値テストメソッドの名前を変更する

constメソッドにprefixオプションを指定することで、作成されるNamedScope、属性値検証メソッドの 名前(プレフィクス)を変更することができる。 定数値名がモデル内で衝突しない場合は、prefixに空文字を与えるのが使いやすい。

class User < ActiveRecord::Base
  const :STATUS, :prefix => '' do
    ENABLE    1
    DISABLE   0
  end
end

user = User.enable.first
user.enable?  # true
user.disable? # false

scope: NamedScopeを作成しない

値が直接DBにない場合、scopeオプションでfalseを指定すると、 定数値を返すメソッドを定義することで各種メソッドを利用できる。

class Entry < ActiveRecord::Base
  # 公開状態[予約、公開、終了]
  const :STATUS, :scope => false, :prefix => '' do
    SCHEDULED 1
    OPENED    2
    FINISHED  3
  end

  scope :scheduled ,lambda {time = Time.now; where('start_at > ? ', time) }
  scope :opened,    lambda {time = Time.now; where('start_at <= ? AND end_at > ?', time, time) }
  scope :finished,  lambda {time = Time.now; where('end_at <= ? ', time) }

  # 公開状態
  def status
    now = Time.now
    case
    when start_at > now
      STATUS::SCHEDULED
    when (end_at >= now and start_at <= now)
      STATUS::OPENED
    else
      STATUS::FINISHED
    end
  end

  # 変更前公開状態
  # status_label_wasやwas_opened?などを使わない場合は不要
  def status_was
    now = Time.now
    case
    when start_at_was > now
      STATUS::SCHEDULED
    when (end_at_was >= now and start_at_was <= now)
      STATUS::OPENED
    else
      STATUS::FINISHED
    end
  end
end

entry = Entry.create(:start_at => Time.now, :end_at => Time.now + 10.days)
entry.status_label
entry.active?

predicate: 属性値テストメソッドを作成しない

predicateオプションでfalseを指定すると、属性値テストメソッドの作成が行われない。

i18n: ラベル名にi18nを利用しない

i18nオプションでfalseを指定すると、constメソッド内の定数値定義の後にラベル名を与えることでラベル名を定義することができる。

# app/models/user.rb
class User < ActiveRecord::Base
  const :STATUS, :i18n => false do
    ENABLE    1, "有効"
    DISABLE   0, "無効"
  end
end

extensions: 定数オブジェクトに追加のメソッドを定義する

ブロック内にメソッド定義を書くと、STAUTS[]やSTATUS.eachの際に取得できる定数オブジェクトに対してメソッドが定義される。 collection_selectの際に表示したいラベル名を複数パターン用意する場合などに利用可能。

class User < ActiveRecord::Base
  const :STATUS do
    ENABLE    1
    DISABLE   0
    # 定数オブジェクトには以下のメソッドが存在するため、これらのメソッドを自由に呼び出すことができる
    # key   名前空間(クラス、モジュール名)を含まない各定数名のシンボル
    # label ラベル名
    # value 定数値
    def code
      '%05d'%value
    end
    # I18nを使ってみる。
    def label2
      I18n.t(key.to_s.downcase, :scope=> 'labels.user.status_label2')
    end
  end
end

# 選択肢に上で定義したcodeメソッドの値を使用する
user = User.new
form_for user do |f|
  f.collection_select(:status, User::STATUS, :value, :code)
  f.collection_select(:status, User::STATUS, :value, :label2)
end

その他

デフォルトでI18nを無効にする

ConstEnum::ActiveRecord.i18nにfalseを設定すると、 constメソッドのi18nオプションの初期値をfalseにすることができます。

# config/initializers/const_enum.rb
ConstEnum::ActiveRecord.i18n = false

# app/models/user.rb
class User < ActiveRecord::Base
  const :STATUS, :prefix => '' do
    ENABLE    1, "有効"
    DISABLE   0, "無効"
  end
end

ラベル名を取得するメソッド名を変更する

ConstEnum::ActiveRecord.label_suffixを設定することで、 ラベル名を取得すためのメソッドの名前(サフィックス)を変更することができる。

# config/initializers/const_enum.rb
ConstEnum::ActiveRecord.label_suffix = '_name' # ラベル名を返すメソッドにつけるサフィックスの指定

Copyright

Copyright © 2012 Synergy Marketing, Inc. See LICENSE for details.