Avoid using enums in ActiveRecord. While they seem like a great idea at first, they can cause problems down the road.
class Document < ActiveRecord::Base
# ✗ Avoid this!
enum status: [:active, :archived]
end
Enums are a way to use numbers instead of strings (eg, 1
instead of 'active'
), but this abstraction can get leaky. In the example above, you can easily use :active
and :archived
as you would use any other value. Rails abstracts away the conversion of them into integers.
Document.where(status: :archived)
# This actually does `Document.where(status: 1)`
However, there are cases where this doesn't apply. For instance:
# ✗ Throws an error
Document.where("status = ?", "archived")
# ✗ Throws an error
Comment.joins(:document).where({ document: { status: :archived }})
# It should instead be written like this:
archived = Document.statuses[:archived]
Comment.joins(:document).where({ document: { status: archived }})
If you must use Enums, always assign explicit values to them. Consider the example above: if we were to add another status, we may be tempted to do it like so:
class Document < ActiveRecord::Base
- enum status: [:active, :archived]
+ enum status: [:pending, :active, :archived]
end
This, however, will break all existing Document records. The new :pending
status will be assigned a value of 0
, which was the previous value of :active
. With this, all previously active documents will now be :pending
, and all previously archived documents will be :active
.
Here are some more arguments against Enums:
Other resources: