Blankman
Blankman

Reputation: 266988

How to create a enum type and default to a specific value for new objects

I have a model

class Transaction < ActiveRecord::Base

end

I have a transaction_type column which is an integer.

How can I create an enumeration that I could map values to names like:

one_time = 1
monthly = 2
annually = 3

So in the db column, the values would be 1, 2 or 3.

Also, whenever I create a new instance, or save a model and the field wasn't set like:

@transaction = Transaction.new(params)

It should default to 1 (on_time).

I'm not sure how I can do this?

Upvotes: 1

Views: 1208

Answers (3)

house9
house9

Reputation: 20614

basically the same answer as Amit, slight variation

class TransactionType
  TYPES = {
    :one_time => 1,
    :monthly => 2,
    :annually => 3
  }

  # use to bind to select helpers in UI as needed
  def self.options
    TYPES.map { |item| [item[0], item[1].to_s.titleize] }
  end

  def self.default
    TYPES[:one_time]
  end
end

one way to control the default value

class Transaction < ActiveRecord::Base
  before_create :set_default_for_type

  def set_default_for_type
    type = TransactionType.default unless type.present?
  end
end

but - best way is to just apply the defaults on your database column and let ActiveRecord get it from there automatically

NOTE: it might also make sense to just have a TransactionType ActiveRecord object instead of above, depends on your situation, i.e.

# on Transaction with type_id:integer
belongs_to :type, class_name: "TransactionType" 

Upvotes: 4

Amit Thawait
Amit Thawait

Reputation: 5292

You can map the values by creating a constant either in the same Transaction model or by creating a new module and place it inside that as explained by @KepaniHaole

In Transaction model, you can do it like :

class Transaction < ActiveRecord::Base

  TRANSACTION_TYPES = { 'one_time' => 1, 'monthly' => 2, 'monthly' => 3 }

end

You can access these values by accessing the constant as

Transaction::TRANSACTION_TYPES['one_time']    # => 1
Transaction::TRANSACTION_TYPES['monthly']     # => 2
Transaction::TRANSACTION_TYPES['monthly']     # => 3

To add a default value to transaction_type column just create a new migration with :

def up
  change_column :transactions, :transaction_type, :default => Transaction::TRANSACTION_TYPES['one_time']
end

With this, every time you create a Transaction object without passing transaction_type, the default value 1 with be stored in it.

Upvotes: 2

sandymatt
sandymatt

Reputation: 5612

Maybe you could try something like this? Ruby doesn't really support c-style enums..

module TransactionType
  ONCE = 1
  MONTHLY = 2
  ANUALLY = 3
end

then you could access their values like so:

@transaction = Transaction.new(TransactionType::ONCE)

Upvotes: 1

Related Questions