Disha
Disha

Reputation: 796

Migrations from scratch breaking as column in model doesn't exist yet

I have following models and association.

class Stock < ApplicationRecord
  has_many :stock_components, -> {order(:position)} 

  ...
  before_save :set_default_values

   def set_default_values
     self.material_cost = 0.0 if self.material_cost.nil?
   end
  ... 
end

When I run migrations from scratch, a migration that inserts a record in this table, breaks at line self.material_cost = 0.0 if self.material_cost.nil? with following -

Caused by:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'stock_components.position' in 'order clause': SELECT `stocks`.* FROM `stocks` INNER JOIN `stock_components` ON `stocks`
.`id` = `stock_components`.`component_id` WHERE `stock_components`.`stock_id` = 1 ORDER BY `stock_components`.`position` ASC

This is because migration for adding position hasn't run yet.

What could be solution for this?

Upvotes: 0

Views: 52

Answers (1)

rewritten
rewritten

Reputation: 16435

That's really unfortunate, but it's a common issue which is almost never addressed.

When a data migration on a model is written, either to change or set values, or to add data, typically one relies on the application model (with all the corresponding callbacks etc).

But then at a later time, more callbacks are added, and previous migrations are broken. Even worse, a later migration might rename or remove a column, and the inserted data is not valid anymore.

The solution is that you should NEVER use application models in a migration, but rather some local model that uses whatever is in the database at the time:

class PopulateStock < ActiveRecord::Migration
  class Stock < ActiveRecord::Model
    self.table_name = 'stocks'
  end

  def up
    Stock.create(...)
  end
end

Now the Stock model that is referenced in the migration is completely defined by the status of the table at the time of migration (no extra columns, no callbacks etc) instead of depending on all the application model.

Unfortunately this means that you have to go through all your app's migrations and create local models for them until migrations can be run.

Upvotes: 2

Related Questions