Search code examples
ruby-on-railspostgresqlactiverecordrails-migrations

Move data from removed column to just created one in Rails migration


I have a table 'Invoices' which contains two boolean columns:

Table name: invoices

id               :integer          not null, primary key
...
sent             :boolean          default(FALSE)
payment_received :boolean          default(FALSE)

This two columns define status of invoice:

def status
  if sent & payment_received
    :paid
  elsif sent | payment_received
    :sent
  else
    :created
  end
end

One day it was desided to remove these boolean columns and create new column that will contain invoice status by the help of Rails enum

status :integer

enum status: [ :created, :sent, :paid ]

So now I need to do 3 things:

  1. Add new column 'status'
  2. Calculate status for existing invoices, update status column
  3. Remove columns 'sent' and 'payment_received'.

How can I do this? I can do this task easily on my local environment, but I can't understand how can I do this on production server. If, for example, I'll create a migration that update my table and a rake task that calculate status, migration pass first and my data from boolean columns will be removed before I can use them.

Note: if somehow it's important: I use Postgres.

Any help is appreciated!


Solution

  • Try the following migration.

    class UpdateInvoicesTable < ActiveRecord::Migration
      def self.up
        add_column :invoices,:status,:string
    
        Invoice.find_in_batches(batch_size: 2000) do |invoices|
          invoices.each do |invoice|
            if invoice.sent & invoice.payment_received
              invoice.status = 'paid'
            elsif invoice.sent | invoice.payment_received
              invoice.status = 'sent'
            else
              invoice.status = 'created'
            end
            invoice.save
          end
        end
    
        remove_column :invoices,:sent
        remove_column :invoices,:payment_received
      end  
    end