将STI添加到现有表

时间:2010-04-11 12:15:51

标签: mysql ruby-on-rails single-table-inheritance

我想使用自定义类型列将STI添加到现有表中。我们称之为taste_type,其对应的模型是Fruit。

在Fruit模型中我有:

set_inheritance_column :taste_type

在我添加STI的迁移中,我有:

class AddSTI < ActiveRecord::Migration
  def self.up
    add_column :fruits, :taste_type, :string, :limit => 100, :null => false
    Fruit.reset_column_information
    Fruit.find_by_id(1).update_attributes({:taste_type => 'Sour'})
  end

  def self.down
    remove_column :fruits, :taste_type
  end

end

当我运行迁移时,出现以下错误:

Mysql::Error: Column 'taste_type' cannot be null: ...

知道发生了什么事吗?如果我在Fruit模型中注释set_inheritance_column,然后在运行迁移后取消注释,我可以运行迁移。显然,我不想这样做。

2 个答案:

答案 0 :(得分:1)

taste_type列不能为空。数据库引发错误,因为您要向具有现有行的表添加新列(不能为空)。

解决此问题的一种方法是向列添加默认值,然后重置默认值。

add_column :fruits, :taste_type, :string, :limit => 100, :null => false, 
      :default => "Sour"
change_column :fruits, :taste_type, :string, :limit => 100, :null => false

Fruit.reset_column_information
Fruit.find_by_id(1).update_attributes({:taste_type => 'Sour'})

其他方法是在截断fruits表后运行迁移。

答案 1 :(得分:0)

对于那些使用Rails 4找到它的人,您可以:

  1. 添加列,最初允许null
  2. 迁移您的数据,确保所有预先存在的记录都具有type
  3. 迁移数据后,使用change_column_null使列为null。

    # my_migration.rb
    
    class MyMigration < ActiveRecord::Migration
      class Fruit < ActiveRecord::Base; end
    
      def up 
        add_column :fruits, :taste_type, :string, limit: 100, default: "Sour" 
    
        Fruit.reset_column_information
        Fruit.find_each do |fruit|
          fruit.update_attributes!(taste_type: 'Sour')
        end
    
        change_column_null :fruits, :taste_type, false
      end
    end
    
  4. http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/change_column_null

    How to change a nullable column to not nullable in a Rails migration?