Search code examples
sqlruby-on-railsactiverecordrails-activerecordrails-migrations

Add a column in a Rails Active Record migration with an initial value based on other columns


I am attempting to add a column to an existing table using an Active Record migration in Rails. I need the column's initial value to be based on other columns in the table. Is there a way to do this in an Active Record migration?

To make it more concrete, let's say I have the following:

my_table
----------------
first_name: text
last_name: text

I want to add a full_name text column with an initial value of concat(first_name, ' ', last_name'. Note that I don't want a default value on the column, as I intend for the application to be populating this going forward (the initial default is just to have a sensible starting value for existing records).

How can I do this in a migration? Ideally I would like to use add_column or similar, though if that can't work a working alternative would be acceptable.

Note that there already exists a nearly identical question (add a database column with Rails migration and populate it based on another column), but none of its answers seem to fully answer this question.


Solution

  • I ended up adding the column using add_column and then using direct SQL to update the value of the column. I used direct SQL and not the model per this answer, since then it doesn't depend on the current state of the model vs. the current state of the table based on migrations being run.

    class AddFullName < ActiveRecord::Migration
      def up
        add_column :my_table, :full_name, :text
        execute "update my_table set full_name = concat(first_name, ' ', last_name)"
      end
    
      def down
        remove_column :my_table, :full_name
      end
    end
    

    That said, if there is a better or more idiomatic approach to this, I'm all ears.