DEV Community

Cover image for Enum on Rails — A shallow dive 💎
Sameer Kumar
Sameer Kumar

Posted on • Updated on

Enum on Rails — A shallow dive 💎

After so long, active again. Let’s have a look at beloved ActiveRecord this time. It packs up too much to be covered in simple glance, one such feature is interpretation of enums in rails. Enums are nothing more than an array technically in other languages but here its high on steroids. Lets try to clean a mess with help of enums.

As always lets create a hypothetical problem first so that we can pretend to solve and learn something from it. Our application has a table for accounts and we have implemented something like below to manage it.

Account table structure: class _CreateAccounts_ < ActiveRecord::Migration\[6.1\]
  def change
    create\_table :accounts do |_t_|
      _t_.string :first\_name
      _t_.string :last\_name
      _t_.string :status

      _t_.timestamps
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Account model:

_\# frozen\_string\_literal: true

_class _Account_ < ApplicationRecord
  validates\_inclusion\_of :status, in: %w\[created active inactive deleted\]
  validates\_inclusion\_of :origin, in: %w\[email facebook google twitter\]
end
Enter fullscreen mode Exit fullscreen mode

Now we try to do something based on our Account model, Lets say for an account which is inactive and came from email origin, send an email.

if @account.status == 'inactive' && @account.origin == 'email'
  p 'Sending an email.'
  _\#  do something
_end
Enter fullscreen mode Exit fullscreen mode

This of course works well, at this point in your career you won’t be writing something that doesn’t work but we want to take our game to next level. One possible way is to use boolean methods like:

class _Account_ < ApplicationRecord
  validates\_inclusion\_of :status, in: %w\[created active inactive deleted\]
  validates\_inclusion\_of :origin, in: %w\[email facebook google twitter\]

  def inactive?
    status == 'inactive'
  end

  def email\_orgin?
    status == 'email'
  end
end
Enter fullscreen mode Exit fullscreen mode

Then it looks a bit more cleaner:

if @account.inactive? && @account.email\_orgin?
  puts 'Sending an email...'
  _\#  do something
_end
Enter fullscreen mode Exit fullscreen mode

Taking it to an ultra pro max level we can substitute it with enums this time. Enums are representation of strings in form of integers. We’ll look into structure soon but lets start with a small migration to represent it:

class AddStatusToAccounts < ActiveRecord::Migration\[6.1\]
  def change
    add\_column :accounts, :status, :integer
  end
end
Enter fullscreen mode Exit fullscreen mode

New account model:

class _Account_ < ApplicationRecord
  enum status: \[:created, :active, :inactive, :cancelled\]
  enum managed\_by: \[:admin, :user\], \_prefix: true
  enum origin: \[:email, :facebook, :google, :twitter\], \_suffix: true
end
Enter fullscreen mode Exit fullscreen mode

Alternatively and better way is to use hash for index consistency:

 

class Account < ApplicationRecord
  enum status: {created: 0, active: 3, inactive: 1, cancelled: 3}
  enum managed_by: [admin: 0, user: 1], _prefix: true
  enum origin: [email: 0, facebook: 1, google: 3], _suffix: true
end
Enter fullscreen mode Exit fullscreen mode

Here these values like email, Facebook, google, twitter, etc are available to rails but in database it is stored as 0, 1, 2, 3 respectively. Kinda intuitive already!

Typically you can use it similarly as a normal value, just like:

if @account.status == :active
  puts 'Account is active'
end
Enter fullscreen mode Exit fullscreen mode

BUT, We didn’t come all this way to do same thing as we could have done in our first attempt. ActiveRecord’s secret love for enum comes in light when we see its built in methods for enums.

As you can infer from these examples, in this case since we have not specified any modifiers, so it is being used as a direct method on model. Like:

@account.created?
@account.active?
@account.inactive?
@account.cancelled?
Enter fullscreen mode Exit fullscreen mode

With prefix option:

@account.managed\_by\_admin?
@account.managed\_by\_user?
Enter fullscreen mode Exit fullscreen mode

With suffix option:

@account.email\_origin?
@account.facebook\_origin?
@account.google\_origin?
@account.twitter\_origin?
Enter fullscreen mode Exit fullscreen mode

Apart from these object level magic, we have some at class/scope level as well:

Account.active
Account.managed\_by\_admin
Account.email\_origin
Enter fullscreen mode Exit fullscreen mode

Let whole reading stuff aside, we can write value even more elegantly [Validations included]:

@account.inactive!  # @account.update(status: :inactive)
@account.managed\_by\_user! # @account.update(managed\_by: :inactive)
@account.google\_origin! # @account.update(orgin: :google)
Enter fullscreen mode Exit fullscreen mode

Photo by Ben White on Unsplash

That was all on fundamentals of Enums on Rails. Well I think, now you have a smile on your face, hence, one on mine. Stay tuned. We’ll catchup again next week to discuss something amazing!

Do follow for more Ruby on Rails posts.

To Connect

==========

🏠 Website: https://hi-sameer.web.app
🏭 LinkedIn: https://www.linkedin.com/in/sameerkumar1612/

Discussion (0)