Rails: ActiveRecord Enum Usage

1 minute read

Let’s have a model called Car and we want to keep information such as whether the car is rented, available or unavailable.

Should we use more than one column? Why?

Let’s imagine that we added these fields to our table as follows.

class AddStatusesToCars < ActiveRecord::Migration
  def change
    add_column :cars, :rented, :boolean
    add_column :cars, :available, :boolean
    add_column :cars, :unavailable, :boolean
  end
end

According to this scenario, the car must be either rented, available or unavailable. It should not be both rented and available at the same time. We can handle this with validation. However, this time, when one is true, the other two columns will be empty. So let’s look at a way to do this in a single column:

class AddStatusToCars < ActiveRecord::Migration
  def change
    add_column :cars, :status, :integer, default: 0
  end
end
class Car < ActiveRecord::Base
  STATUSES = %w{rented available unavailable}

    def status_to_s
      STATUSES[status]
    end

    def available?
      status_to_s == 'available'
    end

    def rented?
      status_to_s == 'rented'
    end

    def unavailable?
      status_to_s == 'unavailable'
    end
end

Let’s look at its usage:

> Car.first.status_to_s
# => “available”

> Car.first.available?
# => true

> Car.first.rented?
# => false

> Car.first.unavailable?
# => false

This may be preferable instead of creating three columns. But, how do we solve the process of creating extra methods?

Let’s call the Enum into play.

Add the status field to our car model:

class AddStatusToCars < ActiveRecord::Migration
  def change
    add_column :cars, :status, :integer, default: 0
  end
end

Define our statuses with enum in our car model.

class Book < ActiveRecord::Base
  enum status: [:available, :rented, :unavailable]
  # or define with number
  # enum status: [
  #   available:   1,
  #   rented:      2,
  #   unavailable: 3
  # ]
end

Let’s look at its usage:

> car = Car.first
> car.status
# => “available”

> car.rented?
# => false

# Change the car status to rented
car.status = :rented
car.rented! # updated
car.rented?
# => true

# To find all rented cars (scope method)
 > Car.rented
# => SELECT "cars".* FROM "cars" WHERE "cars"."status" = ?  [["status", 1]]
# [#<Car:0x007f41d3eeeeee
# id: 1,
# status: 1,
# ]


# To find all unavailable cars (scope method)
> Car.unavailable
# => SELECT "cars".* FROM "cars" WHERE "cars"."status" = ?  [["status", 2]]
# => []  (There isn't any available car)
Ecmel Albayrak

Ecmel Albayrak

Subscribe

* indicates required

Intuit Mailchimp