The docs say:
1 Conversation.statuses # => { "active" => 0, "archived" => 1 }In rare circumstances you might need to access the mapping directly. The mappings are exposed through a class method with the pluralized attribute name
This is not rare! This is critical!
For example, suppose you want to query where the status is not “archived”:
You might be tempted to think that Rails will be smart enough to figure out that
1 Conversation.where("status <> ?", "archived")Rails is not smart enough to know that the ? is for status and that is an enum. So you have to use this syntax:
1 Conversation.where("status <> ?", Conversation.statuses[:archived])You might be tempted to think that this would work:
1 Conversation.where.not(status: :archived)
That throws an ArgumentError
. Rails wants an integer and not a symbol, and symbol does
not define to_i
.
What’s worse is this one:
1 Conversation.where.not(status: "archived")
The problem is that ActiveRecord sees that the enum column is of type integer
and calls #to_i
on the value, so archived.to_i
gets converted to zero. In
fact, all your enums will get converted to zero! And if you use the value of
the enum attribute on an ActiveRecord instance (say a Conversation object),
then you’re using a string value!
If you’re curious what the Rails source is, then take a look here: ActiveRecord::Type::Integer.
Here’s a guaranteed broken bit of code:
1 2 # my_conversation.status is a String! Conversation.where.not(status: my_conversation.status)
You’d think that Rails would be clever enough to see that the key maps to an
enum and then check if the comparison value is a String, and then it would
not call to_i
on the String! Instead, we are effectively running this code:
An acceptable alternative to the last code example would be:
1 Conversation.where.not(Conersation.statuses[my_conversation.status])
If you left out the not
, you could also do:
However, I really would like to simply do these, all of which DO NOT work.:
1 2 3 Conversation.where(status: my_conversation.status) Conversation.where(status: :archived) Conversation.where(status: "archived")This is a companion discussion topic for the original entry at http://www.railsonmaui.com//blog/2014/10/23/enums-and-queries-in-rails-4-dot-1/