126

I have a enum in my Model that corresponds to column in the database.

The enum looks like:

  enum sale_info: { plan_1: 1, plan_2: 2, plan_3: 3, plan_4: 4, plan_5: 5 }

How can I get the integer value?

I've tried

Model.sale_info.to_i

But this only returns 0.

Cleyton
  • 2,338
  • 6
  • 23
  • 39

6 Answers6

166

You can get the integer values for an enum from the class the enum is on:

Model.sale_infos # Pluralized version of the enum attribute name

That returns a hash like:

{ "plan_1" => 1, "plan_2" => 2 ... }

You can then use the sale_info value from an instance of the Model class to access the integer value for that instance:

my_model = Model.find(123)
Model.sale_infos[my_model.sale_info] # Returns the integer value
Shadwell
  • 34,314
  • 14
  • 94
  • 99
  • I like this approach. When using `before_type_cast`, it’ll return a string if you’re on an unsaved record you’ve initialised like `Post.new status: :unapproved`, but an integer if it’s persisted. – dazonic Jun 12 '21 at 15:37
158

You can get the integer like so:

my_model = Model.find(123)
my_model[:sale_info] # Returns the integer value

Update for rails 5

For rails 5 the above method now returns the string value :(

The best method I can see for now is:

my_model.sale_info_before_type_cast

Shadwell's answer also continues to work for rails 5.

Subtletree
  • 3,169
  • 2
  • 18
  • 25
  • 1
    It is because 'enum' will create a method sale_info for your model, use [:sale_info] to get the property value instead of return from sale_info method. – etlds Apr 05 '16 at 00:33
  • 7
    Note that this method does not work if the model has not been saved. The sale_info_before_type_cast value (and my_model[:sale_info]) is still a string if it my_model.sale_info has been assigned a string without a subsequent save. – Tim Smith Oct 09 '16 at 05:49
66

Rails < 5

Another way would be to use read_attribute():

model = Model.find(123)
model.read_attribute('sale_info')

Rails >= 5

You can use read_attribute_before_type_cast

model.read_attribute_before_type_cast(:sale_info)
=> 1
ArashM
  • 1,379
  • 13
  • 18
6

My short answer is Model.sale_infos[:plan_2] in case if you want to get value of plan_2

Brilliant-DucN
  • 706
  • 8
  • 12
6

I wrote a method in my Model to achieve the same in my Rails 5.1 app.

Catering for your case, add this into your Model and call it on the object when needed

def numeric_sale_info
  self.class.sale_infos[sale_info]
end
shrmn
  • 1,303
  • 13
  • 19
0

Most of the solutions here require you to have a record or model class in hand. Here is an approach where you can get the integer value from an enum without creating a record, by using Hash's .key method:

sale_info.key('plan_3')
=> 3

This is particularly useful if you're doing some ETL and mapping raw values to/from string values between systems that depend on the numeric integer value and/or the string value in different scenarios.

Note that this is probably not highly performant, as searching for a value in a hash (as opposed to a key) is not efficient. If you're processing millions of values/second or have an enum with (yuck) hundreds of values, you'll probably want to build a new hash that inverts enum's values and keys so you can do efficient lookups in the opposite direction.

David Hempy
  • 5,373
  • 2
  • 40
  • 68