Reputation: 796
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
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