The simplest Enum you will ever find for your ActiveRecord models

I have been using a really useful snippet for a while now.

While dropping it today into a project I realized just how powerful it is:

  1. it’s a drop-in and will work on any project
  2. it’s database agnostic
  3. it’s dead simple
  4. it’s not sensitive to enum changes
  5. and more and more

Just as an into, an enum is a way to have string represented as integers in your database.

Why?

Because integers are much faster to index and query (at least on mysql).

MySQL has an enum solution but ActiveRecord can’t really use it without some nasty hacking and it’s really messy when you want to add another param.

Enough Said, here’s the snippet

1 2 3 4 5 6 7 8 9
STATUS = { pending: 0, active: 1, inactive: 2, deleted: 3 }
 
def status
STATUS.key(read_attribute(:status))
end
 
def status=(s)
write_attribute(:status, STATUS[s])
end
view raw account.rb hosted with ❤ by GitHub

This gives you the ability to work with the Account model like so:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
>> account = Account.first
Account Load (0.2ms) SELECT `accounts`.* FROM `accounts` LIMIT 1
=> #<Account id: 4, name: "KensoDev", subdomain: "kensodev", user_id: 6, created_at: "2012-05-08 16:06:31", updated_at: "2012-05-08 16:29:11", logo_file_name: nil, logo_content_type: nil, logo_file_size: nil, logo_updated_at: nil, token: "5022N7VSAD", plan_id: 1, project_count: 1, contact_count: 1, quota_used: 0, notification_interval: nil, billing_token: "", status: 1>
>> account.status
=> :active
>> account.status = :pending
=> :pending
>> account.save
SQL (0.1ms) BEGIN
Account Load (0.3ms) SELECT `accounts`.`id` FROM `accounts` WHERE (`accounts`.`subdomain` = BINARY 'kensodev') AND (`accounts`.id <> 4) LIMIT 1
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE (`users`.`id` = 6) LIMIT 1
Plan Load (0.2ms) SELECT `plans`.* FROM `plans` WHERE (`plans`.`id` = 1) LIMIT 1
User Load (0.3ms) SELECT `users`.`id` FROM `users` WHERE (LOWER(`users`.`email`) = LOWER('avi@kensodev.com')) AND (`users`.id <> 6) LIMIT 1
[paperclip] Saving attachments.
AREL (0.2ms) UPDATE `accounts` SET `status` = 0, `updated_at` = '2012-05-08 16:29:40' WHERE (`accounts`.`id` = 4)
[paperclip] Saving attachments.
SQL (1.5ms) COMMIT
=> true
>>

As you can see, it’s being persisted into the database as an integer, but you work with symbols/strings which is much nicer and cleaner.