views:

3412

answers:

5

I have some constants that represent the valid options in one of my model's fields. What's the best way to handle these constants in Ruby?

+2  A: 

I put them directly in the model class, like so:

def MyClass < ActiveRecord::Base
  ACTIVE_STATUS = "active"
  INACTIVE_STATUS = "inactive"
  PENDING_STATUS = "pending"
end

Then, when using the model from another class, I reference the constants

@model.status = MyClass::ACTIVE_STATUS
@model.save
Micah
+8  A: 

You can use an array or hash for this purpose (in your environment.rb):

OPTIONS = ['one', 'two', 'three']
OPTIONS = {:one => 1, :two => 2, :three => 3}

or alternatively an emumeration class, which allows you to enumerate over your constants as well the keys used to associate them:

class Enumeration
  def Enumeration.add_item(key,value)
    @hash ||= {}
    @hash[key]=value
  end

  def Enumeration.const_missing(key)
    @hash[key]
  end   

  def Enumeration.each
    @hash.each {|key,value| yield(key,value)}
  end

  def Enumeration.values
    @hash.values || []
  end

  def Enumeration.keys
    @hash.keys || []
  end

  def Enumeration.[](key)
    @hash[key]
  end
end

which you can then derive from:

class Values < Enumeration
  self.add_value(:RED, '#f00')
  self.add_value(:GREEN, '#0f0')
  self.add_value(:BLUE, '#00f')
end

and use like this:

Values::RED    => '#f00'
Values::GREEN  => '#0f0'
Values::BLUE   => '#00f'

Values.keys    => [:RED, :GREEN, :BLUE]
Values.values  => ['#f00', '#0f0', '#00f']
Mr. Matt
I decided to go with this solution. I have to say, it does just what I want and plays nicely with ActiveRecord. Thank you! :D
Miles
+2  A: 

You can also use it within your model inside a hash like this:


class MyModel

  SOME_ATTR_OPTIONS = {
    :first_option => 1,
    :second_option => 2, 
    :third_option => 3
  }
end

And use it like this:



if x == MyModel::SOME_ATTR_OPTIONS[:first_option]
  do this
end

Dema
+2  A: 

If it is driving model behavior, then the constants should be part of the model:

class Model < ActiveRecord::Base
  ONE = 1
  TWO = 2

  validates_inclusion_of :value, :in => [ONE, TWO]
end

This will allow you to use the built-in Rails functionality:

>> m=Model.new
=> #<Model id: nil, value: nil, created_at: nil, updated_at: nil>
>> m.valid?
=> false
>> m.value = 1
=> 1
>> m.valid?
=> true

Alternatively, if your database supports enumerations, then you can use something like the Enum Column plugin.

Dave