Rails迁移更改列

Rails migration for change column

我们有script/generate migration add_fieldname_to_tablename fieldname:datatype语法用于向模型添加新列。

在同一行,我们是否有用于更改列的数据类型的脚本/生成? 或者我应该直接在我的vanilla迁移中编写SQL吗?

我想将列从datetime更改为date


我认为这应该有效。

1
change_column :table_name, :column_name, :date


如果要在表中更改多个列,也可以使用块。

例:

1
2
3
change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

有关更多详细信息,请参阅Table类的API文档。


我不知道您是否可以从命令行创建迁移来完成所有这些操作,但您可以创建新的迁移,然后编辑迁移以执行此操作。

如果tablename是表的名称,fieldname是字段的名称,并且您希望从日期时间更改为日期,则可以编写迁移来执行此操作。

您可以使用以下命令创建新迁移:

1
rails g migration change_data_type_for_fieldname

然后编辑迁移以使用change_table:

1
2
3
4
5
6
7
8
9
10
11
12
class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

然后运行迁移:

1
rake db:migrate

正如我在前面的答案中发现的那样,需要三个步骤来更改列的类型:

步骤1:

使用以下代码生成新的迁移文件:

1
rails g migration sample_name_change_column_type

第2步:

转到/db/migrate文件夹并编辑您创建的迁移文件。有两种不同的解决方案。

  • 1
    2
    3
    def change
        change_column(:table_name, :column_name, :new_type)
    end
  • 2。

    1
    2
    3
    4
    5
    6
    7
        def up
            change_column :table_name, :column_name, :new_type
        end

        def down
            change_column :table_name, :column_name, :old_type
        end

    第3步:

    不要忘记执行此命令:

    1
    rake db:migrate

    我已经为Rails 4测试了这个解决方案,它运行良好。


    使用Rails 5

    来自Rails指南:

    If you wish for a migration to do something that Active Record doesn’t know how to reverse, you can use reversible:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
      def change
        reversible do |dir|
          change_table :tablename do |t|
            dir.up   { t.change :fieldname, :date }
            dir.down { t.change :fieldname, :datetime }
          end
        end
      end
    end

    只需生成迁移:

    1
    rails g migration change_column_to_new_from_table_name

    像这样更新迁移:

    1
    2
    3
    4
    5
    class ClassName < ActiveRecord::Migration
        change_table :table_name do |t|
          t.change :column_name, :data_type
        end
    end

    最后

    1
    rake db:migrate


    使用迁移更改数据类型的另一种方法

    步骤1:
    您需要使用迁移删除故障数据类型字段名称

    例如:

    1
    rails g migration RemoveFieldNameFromTableName field_name:data_type

    这里不要忘记为您的字段指定数据类型

    第2步:
    现在,您可以添加具有正确数据类型的字段

    例如:

    1
    rails g migration AddFieldNameToTableName field_name:data_type

    就是这样,现在你的表将添加正确的数据类型字段,快乐红宝石编码!


    这都是假设列的数据类型具有任何现有数据的隐式转换。我遇到过现有数据的几种情况,假设String可以隐式转换为新的数据类型,假设是Date

    在这种情况下,了解您可以使用数据转换创建迁移很有帮助。就个人而言,我喜欢将这些放在我的模型文件中,然后在迁移所有数据库模式并且稳定后删除它们。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /app/models/table.rb
      ...
      def string_to_date
        update(new_date_field: date_field.to_date)
      end

      def date_to_string
        update(old_date_field: date_field.to_s)
      end
      ...
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
        def up
            # Add column to store converted data
            add_column :table_name, :new_date_field, :date
            # Update the all resources
            Table.all.each(&:string_to_date)
            # Remove old column
            remove_column :table_name, :date_field
            # Rename new column
            rename_column :table_name, :new_date_field, :date_field
        end

        # Reversed steps does allow for migration rollback
        def down
            add_column :table_name, :old_date_field, :string
            Table.all.each(&:date_to_string)
            remove_column :table_name, :date_field
            rename_column :table_name, :old_date_field, :date_field
        end

    要在编辑默认值时完成答案:

    在rails控制台中:

    1
    rails g migration MigrationName

    在迁移中:

    1
    2
    3
      def change
        change_column :tables, :field_name, :field_type, default: value
      end

    看起来像:

    1
    2
    3
      def change
        change_column :members, :approved, :boolean, default: true
      end