I am trying to figure out what is the best way to store an enum value in activerecord but convert it to a \'title\' for display in an app.
I.E.
Review Enum:
ActiveRecord enums is the best way to go since it's a part of the framework (since version 4.1).
Its usage is quite simple:
Migration:
class AddEnumToMyModel < ActiveRecord::Migration
def change
add_column :my_model, :status, :integer, default: 0
end
end
Model:
class MyModel < ActiveRecord::Base
enum status: [:draft, :beta, :public]
end
Then use it a will:
MyModel.draft # gets all drafts
MyModel.last.draft? # checks if the last model is draft
MyModel.last.status # gets the string description of the status of my model
For mode information refer to documentation.
there are a lot of posts about this issue, i guess that this points to most of them: http://thinkinginrails.com/2010/04/using-enums-for-constants/
i think that this is an over engineered thing, that you don't need in a dynamically typed language like ruby.
just use strings!
you could then use that like:
class Review < ActiveRecord::Base
validates_inclusion_of :status, :in => ["UNREVIEWED", "REVIEWED", "FLAGGED"]
def status
read_attribute(:status)
end
def status= (value)
write_attribute(:status, value)
end
end
While I agree that @Godsaur answer is correct - I personally don't like the approach of storing integer values to represent meaningful string equivalents (provided that enough database indexing is made and/or the cost of querying strings in the DB engine is similar to that of querying integers).
My approach is usually storing the text values in the database (for easier understanding of DB records).
class MyModel < ActiveRecord::Base
STATUSES = HashWithIndifferentAccess.new({unverified: 'unverified', reviewed: 'reviewed', flagged: 'flagged'})
#the text values are similar to their symbols key
#you could also define additional attributes for each key if needed. Ex:
#STATUSES = {unverified: {title: 'Unverified Text Title', txt: 'unverified'}, ...}
# assuming a 'status' field
scope :unverified, -> { where(status: STATUSES[:unverified]) }
def unverified?
status == STATUSES[:unverified]
end
# Or
STATUSES.each do |sym, val|
define_method("#{sym}?") {status == val}
end
end
<%= MyModel::STATUSES[@my_model.status] %> or
<%= MyModel::STATUSES[@my_model.status].title %>
Using @Godsaur example.
class MyModel < ActiveRecord::Base
enum status: [:draft, :beta, :public]
end
You can get the string value as:
MyModel.last.status
=> "beta"
But if you want a "title" you can:
MyModel.last.status.titleize
=> "Beta"
I agree with @tamersalama. Here's a simple way to do it using strings in the DB with a custom Enum class. Note that this also supports human readable names for use in dropdown menus.
https://gist.github.com/alexch/a7be54e1b085718473ff
SQL:
Table name: snacks
id :integer
ice_cream :string
Rails:
class Snack < ActiveRecord::Base
FLAVORS = Enum.new [
[:vanilla, "Vanilla"],
[:chocolate, "Chocolate"],
[:rocky_road, "Rocky Road"]
])
]
end
HTML:
<%= simple_form_for @snack do |f| %>
<%= f.collection_select :ice_cream, Snack::FLAVORS, :value, :label %>
<% end %>