Rails provides better ActiveRecord enum assertions


ActiveRecord’s enum provides an easy way to map values to integers. However, it has been lagging in the built-in assertions available. Recently, Rails added options to prevent enum values from being defined erroneously. This does not covert the plethora of possible errors that can be encountered with enums.

Before

It was possible to set enum to empty values. This does not cause a drastic failure however it opens up a vulnerability. Further, it was also possible to define erroneous values to an enum like numbers or empty hashes.

Let’s see how the current implementation looks like. Consider this ActiveRecord model.

class Blog < ApplicationRecord
  enum :status
  validates :status, inclusion: {in: ["draft", "reviewed", "published"]}
end

Let’s instantiate a new object.

> Blog.new
=> #<Blog id: nil, title: nil, status: nil, created_at: nil, updated_at: nil>

> Blog.new(status: "review")
=> Traceback (most recent call last):
        1: from (irb):2
ArgumentError ('review' is not a valid status)

As you can see an ArgumentError error is only thrown for erroneous values.

After

Thanks to this PR the missing assertions have been added.

Now let’s see what happens when instantiating a new object.

> Blog.new
=> Traceback (most recent call last):
        4: from (irb):1
        3: from (irb):2:in `rescue in irb_binding'
        2: from app/models/blog.rb:14:in `<main>'
        1: from app/models/blog.rb:17:in `<class:Blog>'
ArgumentError (Enum values [] must not be empty.)

It preemptively catches errors now! Further, a clearer message is now given when setting enum values to Integer options.

class Blog < ApplicationRecord
  enum status: ['abc', 1]
end

This is what happens,

> Blog.new
=> Traceback (most recent call last):
        3: from (irb):1
        2: from app/models/blog.rb:14:in `<main>'
        1: from app/models/blog.rb:17:in `<class:Blog>'
ArgumentError (Enum values ["abc", 1] must only contain symbols or strings.)

Prior to this change a generic error statement used to be raised which read ArgumentError (Enum values ["abc", 1] must be either a hash, an array of symbols, or an array of strings.). The updated error statement highlights the actual error in value setting.

Join Our Newsletter