我正在改变一个基础模型的inheritance_column值,它是用STI扩展的,在一个现有的应用程序中。如何编写迁移以使现有列符合新的inheritance_column?
这是我的第一次尝试:
class MigrateStoryTypes < ActiveRecord::Migration
def self.up
Story.all.each { |story|
new_story_type = story.story_type.camelize + 'Story'
puts "changing #{story.id}'s story_type from #{story.story_type} to #{new_story_type}"
story.update_column :story_type, new_story_type
}
end
def self.down
Story.all.each { |story|
new_story_type = story.story_type.underscore.gsub /_story/, ''
puts "changing #{story.id}'s story_type from #{story.story_type} to #{new_story_type}"
story.update_column :story_type, new_story_type
}
end
end但是,以下情况未能做到这一点:
ActiveRecord::SubclassNotFound:单表继承机制未能找到子类:“clean_slate”。引发此错误是因为保留列“story_type”用于在继承的情况下存储类。如果您不希望将该列用于存储继承类或覆盖Story.inheritance_column以使用另一列来获取该信息,请重命名该列。
是否有一种通过ActiveRecord直接执行此操作的方法,还是需要使用临时列、SQL等?
发布于 2016-10-08 22:32:39
在迁移中使用模型通常是个坏主意,因为模型类假设它们知道数据库结构是什么,但是迁移是为了操纵数据库结构。您的错误消息只是模型类与数据库不同步的一种情况。一旦Story.all试图实例化模型,您就会得到ActiveRecord::SubclassNotFound STI异常,因为ActiveRecord希望在story_type中找到类名,但在story_type中仍然有旧的字符串类型:在数据库修复之前,无法使用模型修复数据库。
我建议您假装您的模型在迁移中根本不存在,如果您直接使用数据库,您将有一个更好的时间。您只有两个story_type值,所以SQL非常简单:
def up
connection.execute(%q{
update stories
set story_type = case story_type
when 'whatever1' then 'Whatever1Story'
when 'whatever2' then 'Whatever2Story'
end
})
end只有两个价值观,你知道它们是什么,所以不要浪费时间试图变得聪明。
https://stackoverflow.com/questions/39934662
复制相似问题