goldie
goldie

Reputation: 77

How to find constant id in Rails migration?

I'm adding a new column to the table in Rails app and not sure how to set a default value through constant

I defined constant in User.rb model:

USER_TYPE = [
    { id: 1, name: "User" },
    { id: 2, name: "Admin" },
    { id: 3, name: "Super Admin" }
  ].freeze

and generated new migration

class AddAccountTypeIdInAccounts < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :user_type_id, :integer, :default => ?
  end
end

What should be instead of '?' to save USER_TYPE with id 1 and name "User" from constant as the default value of new User?

Upvotes: 0

Views: 200

Answers (2)

Wender Freese
Wender Freese

Reputation: 117

As your specific question was answered in the last comment I'll let some points just to drive your imagination to better options you have for this problem.

Let's imagine if tomorrow you need to change the default value of this specific column, you will need to create a new migration, and if you need to change this 20 times you'll need to create 20 new migrations.

The option above is not scalable.

You should probably let the default nil in migration and use ActiveRecord callbacks or even better another module (service or action) that will take care of the create action to you and set the default value.

# models/user
# option 1
class User < ApplicationRecord
  USER_TYPE = [
    { id: 1, name: "User" },
    { id: 2, name: "Admin" },
    { id: 3, name: "Super Admin" }
  ].freeze

  before_create do
    self.user_type_id = USER_TYPE.first[:id]
  end
end

# services/user_creator_service
# option 2
class UserCreatorService
  def self.call(user)
    user.user_type_id = User::USER_TYPE.first[:id]
    user.save
  end
end

Upvotes: 0

fphilipe
fphilipe

Reputation: 10054

add_column :users, :user_type_id, :integer, :default => 1

Seriously, why do you want to define the default based off of a constant that lives in the app code? The migration is something that you will run at a certain point in time, it's not code that you'll maintain down the line. There's little point in referencing app code in migrations because the app will evolve and references will change. You don't want to maintain migrations.

Of course you could also reference the value stored in that constant, maybe it serves as documentation for you. In that case:

add_column :users, :user_type_id, :integer, :default => User::USER_TYPE.first[:id]

(Not sure if USER_TYPE is defined inside class User; if not, omit User:: above.)

Upvotes: 3

Related Questions