在Rails

时间:2015-07-22 01:54:26

标签: ruby-on-rails ruby-on-rails-4 rails-activerecord rails-migrations

Rails guides to active record migrations表示你可以

change_column_default :products, :approved, from: true, to: false

我在Rails中有一个change方法,类似于以下内容:

change_column_default :people, :height, from: nil, to: 0

意图从没有任何默认值,到默认值为零。

然而,当我尝试回滚时,我得到了

ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

考虑到我给Rails一个fromto,为什么不接受呢?

我正在使用Rails 4.2.0。

7 个答案:

答案 0 :(得分:17)

如果您使用mysql作为适配器,那么根据此链接http://apidock.com/rails/ActiveRecord/ConnectionAdapters/AbstractMysqlAdapter/change_column_default,您的change_column_default迁移就像这样运行

def change_column_default(table_name, column_name, default) #:nodoc:
 column = column_for(table_name, column_name)
 change_column table_name, column_name, column.sql_type, :default => default
end

因此,当您拨打change_column并根据此链接时,您会看到其内部调用change_column_default http://edgeguides.rubyonrails.org/active_record_migrations.html  change_column迁移是不可逆转的。

这表明您获得ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

的原因

因此,如果您想使用change_column_default运行迁移,则必须添加def updef down

我建议使用change_column,因为它已在change_column_default中调用。

def up
 change_column :people, :height, :integer, default: 0
end

def down
 change_column :people, :height, :integer, default: nil
end

答案 1 :(得分:12)

在Rails 5 +中使用fromtoadded

问题中链接的指南适用于Edge Rails,而不适用于Rails的发布版本。

change_column_default的可逆语法是拉取请求20018的结果。 pull请求还更新了Edge Rails的Rails指南。

来自activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb

-      def change_column_default(table_name, column_name, default)
+      # Passing a hash containing +:from+ and +:to+ will make this change
+      # reversible in migration:
+      #
+      #   change_column_default(:posts, :state, from: nil, to: "draft")
+      #
+      def change_column_default(table_name, column_name, default_or_changes)

拉取请求是在2015年6月27日提出的,这比2015年8月1日发布的任何版本的Rails更新。

migration for Rails 4.2.3的文档反映了可逆语法尚不可用的事实:

change_column_default :products, :approved, false

答案 2 :(得分:2)

如果您对迁移文件有疑问,请将您的迁移更改为这种格式。

change_column_default :table_name, :column_name, from: nil, to: "something"

答案 3 :(得分:1)

截至2016年10月,此功能(使用to:from: change_column_default可以反转)现在可在5.x分支上使用。不幸的是,它不具备4.2.x或更低版本。 :(

验证:rails项目中的git tag --contains f9c841927ac3d1daea2a9cebf08b18e844e5eec5

答案 4 :(得分:0)

首先,Jonathan Allard表示fromto不在方法来源中,这意味着change_column_default不接受它。就像这样:

def sum(a)
  return a
end

现在,如果您尝试将两个变量传递给它,例如sum(a, b)或任何它将不接受该权限。这是您尝试使用fromto进行的操作。

现在正确的语法是:

change_column_default(:people, :height, 0)

该方法不接受fromto(因为它是如此定义的,即使它们是散列键,如果该方法不使用该键值对在任何地方它都是没用的)如果它是一个新列,显然它将具有默认值nil(如果之前没有设置)并假设列height是否类型为{{ 1}}并且你给它默认值integer它将a存储为默认值(不是100%肯定但是尝试从rails控制台执行此操作)。使用当前默认值的轨道并不重要,它只需要新的默认值。因此,如果当前默认值为0并且您将其设置为0则不会投诉。它是您的数据库,您希望如何处理它。如果你做错了,如果将nil分配给string,数据库会中断它,那么它显然会抛出错误。

现在,一旦此迁移已经运行,它就会将默认值设置为boolean,现在rails不知道以前的默认值是什么。因为它消失了,它没有存储在任何地方。这就是为什么0是不可逆转的迁移。如果您尝试将其回滚,则在change_column_default方法的情况下为您提供ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration。意味着你曾经使用过:

change

因此,对于此类迁移,我们使用方法def change change_column_default(:people, :height, 0) end up

down

希望这有帮助。

答案 5 :(得分:0)

只是补充几点。如果你坚持使用不支持可逆change_column_default的Rails版本,那么解决问题的一个选择是:

def change
    # If your dataset is small, just cache in memory, if large, consider file dump here:
    cache = Table.all
    # Full column def important for reversibility
    remove_column :table, :column, :type, { config_hash }
    # Re-add the column with new default:
    add_column  :table, :column, :type, { config_hash, default: 0 }
    # Now update the data with cached records (there might be more efficient ways, of course):
    cache.each do |rec|
        Table.find(rec.id).update(column: rec.column)
    end
end

答案 6 :(得分:-3)

当您尝试降级数据类型时,在这种情况下从value(0)升级到nil,rails会抱怨此错误。因为它可能会丢失数据

另一个例子是来自string - > integer

这是一个非常good article explain the same

更新

您的反向迁移似乎在change_column_default command_recorder中调用了(activerecord-4.2.0/lib/active_record/migration/command_recorder.rb#76),请检查您是否将nil设置为默认值。

UPDATE2

事实证明,如果你在迁移中使用change,那些必须能够逆转

但是通过change方法,change_column不可逆。因此,您必须使用旧的rails迁移方法updown

阅读本文解释scenario