Let’s say I’m starting out with this model:
class Location < ActiveRecord::Base
attr_accessible :company_name, :location_name
end
Now I want to refactor one of the values into an associated model.
class CreateCompanies < ActiveRecord::Migration
def self.up
create_table :companies do |t|
t.string :name, :null => false
t.timestamps
end
add_column :locations, :company_id, :integer, :null => false
end
def self.down
drop_table :companies
remove_column :locations, :company_id
end
end
class Location < ActiveRecord::Base
attr_accessible :location_name
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :locations
end
This all works fine during development, since I’m doing everything a step at a time; but if I try deploying this to my staging environment, I run into trouble.
The problem is that since my code has already changed to reflect the migration, it causes the environment to crash when it attempts to run the migration.
Has anyone else dealt with this problem? Am I resigned to splitting my deployment up into multiple steps?
UPDATE It appears I am mistaken; when migrating a coworker’s environment we ran into trouble, but staging updated without issue. Mea Culpa. I’ll mark @noodl’s reply as the answer to bury this, his post is good advice anyway.
I think the solution here is to not write migrations which have any external dependencies. Your migrations should not depend on the past or current state of your model in order to execute.
That doesn’t mean that you can’t use your model objects, just that you shouldn’t use the versions found in whatever version of your code happens to be installed when you run a particular migration.
Instead consider redefining your model objects within your migration file. In most cases I find that an empty model class extending
ActiveRecord::Baseor a very stripped down version of the model class I was using at the time I wrote the migration allows me to write a reliable, future proof, migration without needing to convert ruby logic into SQL.