Rails Models: how would you create a pre-defined set of attributes? Rails Models: how would you create a pre-defined set of attributes? ruby-on-rails ruby-on-rails

Rails Models: how would you create a pre-defined set of attributes?


I assume that you are going to have more than a few of these multiple-choice attributes, and would like to keep things tidy.

I would recommend the store it in the database approach only if you want to modify the choices at runtime, otherwise it would quickly become a performance hit; If a model has three such attributes, it would take four database calls instead of one to retreive it.

Hardcoding the choices into validations is a fast way, but it becomes tedious to maintain. You have to make sure that every similar validator and drop-down list etc. use matching values. And it becomes quite hard and cumbersome if the list becomes long. It's only practical if you have 2-5 choices that really won't change much, like male, female, unspecified

What I'd recommend is that you use a configuration YAML file. This way you can have a single tidy document for all your choices

# config/choices.ymlmorality:  - Good  - Evilgenre:  - Action  - Suspense  - Westernhair_color:  - Blond  - Brown  - Black

Then you can load this file into a constant as a Hash

# config/initializers/load_choices.rbChoices = YAML.load_file("#{Rails.root}/config/choices.yml")

Use it in your models;

# app/models/character.rbclass Character < ActiveRecord::Base  validates_inclusion_of :morality, in: Choices['morality']  validates_inclusion_of :genre, in: Choices['genre']  # etc…end

Use them in views;

<%= select @character, :genre, Choices['genre'] %>

etc…


Put simply, you're asking how to enumerate ActiveRecord attributes. There are a lot of discussions around the web and even on SO for using enums in rails applications, e.g. here, here or here to name a few.

I never used one of the many gems there are for enums, but active_enum gem sounds particularly suited for your use case. It doesn't have the downsides of an activerecord-backed attribute set and makes maintenance of attribute values a piece of cake. It even comes with form helpers for formtastic or simple form (which I assume could help you for attribute selection in your character search).


If a change in any of these attributes would be strongly tied to a change in the code (ie: When a new Hair Color is introduced, a new page is created or a new action is implemented), then I'd say add them as a string hash (option 1). You could store them in the Character model as a finalized hashes with other meta-data.

class Character < ActiveRecord::Base  MORALITY = {:good => ['Good' => 'Person is being good'], :evil => ['Evil' => 'Person is being Evil']}  ...endCharacter.where(:morality => Character::MORALITY[:good][0])

Edit to add the code from comment:

Given Character::MORALITY = {:good => {:name => 'Good', :icon => 'good.png'}, ...

- Character::MORALITY.each do |k,v|   = check_box_tag('morality', k.to_s)  = image_tag(v[:icon], :title => v[:name])= Character::MORALITY[@a_character.morality.to_sym][:name]