Alex Rivera | Logout

Proper storage of "enumeration" models in Rails

Asked 2010-11-15T22:43:12.913
18

Apologies if the question is a little imprecise, but I'll describe my problem below.

I'm setting up some models in a Rails project, and one thing I've noticed I'm running into more than a few times is dealing with attributes that meet the following criteria:

  • They can be set to one of a small, predefined set of values
  • Those values need to have both a name and an identifier (whether a numeric id, code, whatever)
  • The values would only ever change as the result of a good deal of code change.

For example, one of my models should have a status field that can be set to one of: Defining, Executed, or Completed. I need to show those specific words within the interface, but I don't want to store the strings in the DB in case I need to change them in the future (or internationalize, or whatever.)

The obvious option is to define models for each of these models, but that seems to present a good deal of overhead in maintaining the models, ensuring that I write migrations between environments, etc. for each one of these, which seems like a lot of overhead.

The other option is to store it as an integer, and whip up an "enumeration" type class that stores the translation of those values - this would probably work fine, but I'm concerned that I'll lose associations and other handy stuff I get from ActiveRecord models.

Any advice on the best way to handle this situation?

Edit
Report

1 Answer

12

Define a varchar or ENUM in the database and validate the field in the model:

validates_inclusion_of :status, :in => %w(Defining Executed Completed)

Rails will treat it like a string field, but it still validates what the values are.

If you really need to abstract the text of the status field, you could just save it as an integer:

class Foo < ActiveRecord::Base
  STATUS_DESCRIPTIONS = %w(Defining Executed Completed)

  def status
    STATUS_DESCRIPTIONS[ read_attribute(:status) ]
  end
end

If it gets any more complicated than that, you should try @Beerlington's gem.

answered 2010-11-16T02:25:16.137

Your Answer