简体   繁体   中英

rails migration version compatibility

Here is the scenario

production/staging code is on version X

Version X of code

# order model
class Order < ActiveRecord::Base
  has_many :payment_transactions
  # has column for check_number

  def update_report
    ReportTable.where(:order_id => id).first.update_attributes(:check_number => check_number)
  end
end

# payment_transaction model
class PaymentTransaction < ActiveRecord::Base

end

Version X + 5 of code

# migration
Order.all.map{|x| x.update_report }

Version X + 10 of code (current)

# migration
add_column :payment_transactions, :check_number, :integer

# order model
class Order < ActiveRecord::Base
  has_many :payment_transactions
  # moved the column check_number to payment_transactions

  def check_number
    self.payment_transactions.where(:method => 'check').blank? ? nil : self.payment_transactions.where(:method => 'check').first.check_number
  end

  def update_report
    ReportTable.where(:order_id => id).first.update_attributes(:check_number => check_number)
  end
end

# payment_transaction model
class PaymentTransaction < ActiveRecord::Base
  # has column for check_number
end

Now when i update the code on staging environment to the latest version (X+10) and run migration, the migration on X+5 fails because it tries to run this

def check_number
  self.payment_transactions.where(:method => 'check').blank? ? nil : self.payment_transactions.where(:method => 'check').first.check_number
end

and payment_transaction will not get check_number field until X+10 migration.

Whats the best way to handle this?

I would comment the update_report call on the X+5 migration, run it, then run the snippet on rails console after I'm done.

Or change the migration to perform a direct SQL query:

execute "update report_tables set check_number = x.check_number ...."

If you can't avoid the models in the migration then, change the X+5 migration to:

Order.all.each do |o|
  ReportTable.where(:order_id => o.id).first.update_attributes(:check_number => o.check_number)
end

This will continue to reference the order's check number attribute which should still be there at that time.

I ended up moving the this code form migration in X+5

Order.all.map{|x| x.update_report }

to migration in X+10

# migration
add_column :payment_transactions, :check_number, :integer
Order.all.map{|x| x.update_report }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM