假设我开始使用这个模型:
class Location < ActiveRecord::Base
attr_accessible :company_name, :location_name
end
现在我想将其中一个值重构为关联模型。
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
这一切在开发过程中都很好,因为我一步一步都做到了;但如果我尝试将其部署到我的临时环境中,我就会遇到麻烦。
问题在于,由于我的代码已经更改以反映迁移,因此在尝试运行迁移时会导致环境崩溃。
还有其他人处理过这个问题吗?我是否已经辞职将我的部署分成多个步骤?
更新看来我错了;在迁移同事的环境时,我们遇到了麻烦,但暂存更新没有问题。 Mea Culpa。我会将@ noodl的回复标记为埋葬这个的答案,无论如何,他的帖子都是好建议。
答案 0 :(得分:9)
我认为这里的解决方案是不编写具有任何外部依赖关系的迁移。您的迁移不应依赖于模型的过去或当前状态才能执行。
这并不意味着您无法使用模型对象,只是在运行特定迁移时不应使用在任何版本的代码中找到的版本。
而是考虑在迁移文件中重新定义模型对象。在大多数情况下,我发现扩展ActiveRecord::Base
的空模型类或我编写迁移时使用的模型类的非常精简的版本允许我编写可靠的,未来证明,迁移而无需将ruby逻辑转换为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
答案 1 :(得分:0)
运行迁移时会出现什么错误?只要您的rake文件和迁移不使用您的模型(并且它们不应该),您应该没问题。
您还需要在迁移的self.down中切换drop_table和remove_column行的顺序。