Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper storage of "enumeration" models in Rails

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?

like image 857
Ryan Brunner Avatar asked Nov 15 '10 22:11

Ryan Brunner


4 Answers

Check out the ruby gem I've been working on called classy_enum. I'm pretty sure it does exactly what you're looking for. The README has some example usage, but the premise is that it lets you define multiple enum members as classes that can have different properties.

like image 84
Peter Brown Avatar answered Oct 17 '22 19:10

Peter Brown


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.

like image 21
Adam Lassek Avatar answered Oct 17 '22 20:10

Adam Lassek


I was looking for a similar solution when I ran into the enumerize gem. I like its clean and simple DSL.

If your states contain a lot of state specific knowledge, then the state machine gen suggested by scaney might be a good idea. The other option is to use the good old state pattern with the state_pattern gem.

like image 2
Pascal Lindelauf Avatar answered Oct 17 '22 18:10

Pascal Lindelauf


sounds like you might want a state_machine, see here: https://github.com/pluginaweek/state_machine

like image 1
scaney Avatar answered Oct 17 '22 20:10

scaney