开发者

How do you deal with breaking changes in a Rails migration?

开发者 https://www.devze.com 2023-02-04 22:18 出处:网络
Let\'s sa开发者_开发问答y I\'m starting out with this model: class Location < ActiveRecord::Base

Let's sa开发者_开发问答y 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::Base or 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.

#20110111193815_stop_writing_fragile_migrations.rb
class StopWritingFragileMigrations < ActiveRecord::Migration
  class ModelInNeedOfMigrating < ActiveRecord::Base
    def matches_business_rule?
      #logic copied from model when I created the migration
    end
  end
  def self.up
    add_column :model_in_need_of_migrating, :fancy_flag, :boolean, :default => false

    #do some transform which would be difficult for me to do in SQL
    ModelInNeedOfMigrating.all.each do |model|
      model.update_attributes! :fancy_flag => true if model.created_at.cwday == 1 && model.matches_business_rule?
      #...
    end
  end

  def self.down
    #undo that transformation as necessary
    #...
  end
end


What error are you getting when you run the migrations? You should be fine as long as your rake files and migrations don't use your models (and they shouldn't).

You'll also want to switch the order of your drop_table and remove_column lines in the self.down of your migration.

0

精彩评论

暂无评论...
验证码 换一张
取 消