How to Store Enum as String to Database in Rails

Possibility of mapping enum values to string type instead of integer

As far as I know it's not possible with Active Record's built-in enum functionality. However, there are a few popular 3rd party gems that do this. The closest match to what comes with Active Record are probably enumerize and SimpleEnum.

However, if you're looking for something a little different, I'd recommend ClassyEnum (full disclosure: I wrote it). Here are some of my notes on the difference between enumerize and SimpleEnum vs ClassyEnum:

Class-less enums (enumerize, SimpleEnum) are great for simple use
cases where you just need a field to represent one of a fixed set of
values. The main issue I have with this solution is that it encourages
conditionals scattered throughout your models, controllers and views.
It's tempting to use these gems because they are the simplest to
implement, but the long term payoff just isn't there IMO for anything
but the simplest cases.

ClassyEnum was designed to solve the problem of having scattered
conditional logic related to the different enums. You can still use it
for simple collections that don't have logic, but when you do need to
add logic (and you almost certainly will), you can push that into the
individual enum classes and take advantage of polymorphism.

How can I cast a enum string value to column type?

The cast method casts a value from user input when it is assigned to an instance. In the case of enum when you assign a string value it remains a string value. It is converted to an integer only when it is persisted in DB.

class Order < ActiveRecord::Base
enum status: {confirmed: 1, cancelled: 2}
end

# this is where the `cast` method is called
@order.status = "cancelled"

# still a string since the `cast` method didn't do anything.
@order.status # => "cancelled"

What you really need is the serialize method. It casts a value from a ruby type to a type that the database knows how to understand.

Order.attribute_types["status"].serialize("cancelled") # => 2

How can I display enum string key instead of integer value in SQL query?

You are asking the DB for info using SQL and so it will not have any knowledge of your Rails enums. You need to use Rails to make the query:

Animals.all.group(:sound).count(:sound)

=> {"bark"=>2, "meow"=>4, "moo"=>3}

For a pure sql answer with Postgresql:

SELECT temp.sound_count,
CASE
when temp.sound = 0 then 'bark'
when temp.sound = 1 then 'meow'
when temp.sound = 2 then 'moo'
END
AS my_sound
FROM (SELECT COUNT(s.sound) as sound_count, a.sound from animals a
GOUP BY a.sound)
AS temp;

How do you use LIKE query for enum in rails?

Enums are normally stored as integers in the database. The mapping to a label is done on application level. The database is not aware of the labels.

This means you'll have to figure out what labels match your criteria on application level. Then convert them into their integer values (which are used in the database). One way to achieve this would be to use grep in combination with a regex that matches your requirements.

# find the matching labels
labels = ConfirmedTask.task_statuses.keys.grep(/pend/i)
# convert them into their integer values
values = labels.map(&ConfirmedTask.task_statuses)
# create your query
ConfirmedTask.where('task_status IN (?)', values)

Somewhat easier would be to drop the label to value translation and let Rails figure this out. This can be done by passing the array of labels to a normal where call (with a non-SQL string argument).

# find the matching labels
labels = ConfirmedTask.task_statuses.keys.grep(/pend/i)
# pass labels to `where` and let Rails do the label -> integer conversion
ConfirmedTask.where(task_status: labels)

I'm not 100% sure if an array of strings is allowed as the where condition of an enum attribute. The documentation uses symbols. If the above does not work, map the strings into symbols with .map(&:to_sym).



Related Topics



Leave a reply



Submit