Rails迁移更改列

pap*_*del 319 migration ruby-on-rails

我们有script/generate migration add_fieldname_to_tablename fieldname:datatype将新列添加到模型的语法.

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

我想将列更改datetimedate.

Ale*_*ban 533

我认为这应该有效.

change_column :table_name, :column_name, :date
Run Code Online (Sandbox Code Playgroud)

  • @b_ayan:据我所知,迁移名称中唯一神奇的词是"添加"和"删除". (13认同)
  • 创建迁移时,请为其指定名称(例如,上述问题中的add_fieldname_to_tablename).如果它以"添加"或"删除"开头,则迁移将自动填充代码以添加或删除列,这样可以节省您自己编写代码的时间. (6认同)
  • 同样值得注意的是,你应该用单独的`up`和`down`动作替换通常的`change`动作,因为`change_column`是一个不可逆转的迁移,并且如果你需要回滚会引发错误. (4认同)
  • @QPaysTaxes up 应包含您想要更改列的内容,down 应包含如何反转该更改。 (3认同)

Joh*_*ohn 98

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

例:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end
Run Code Online (Sandbox Code Playgroud)

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


Rya*_*yan 86

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

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

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

rails g migration change_data_type_for_fieldname
Run Code Online (Sandbox Code Playgroud)

然后编辑迁移以使用change_table:

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
Run Code Online (Sandbox Code Playgroud)

然后运行迁移:

rake db:migrate
Run Code Online (Sandbox Code Playgroud)


Abo*_*abi 31

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

步骤1:

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

rails g migration sample_name_change_column_type
Run Code Online (Sandbox Code Playgroud)

第2步:

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

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end
    
    Run Code Online (Sandbox Code Playgroud)

2.

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end
Run Code Online (Sandbox Code Playgroud)

第3步:

不要忘记执行此命令:

rake db:migrate
Run Code Online (Sandbox Code Playgroud)

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


Mr.*_*Tao 11

使用Rails 5

来自Rails指南:

如果您希望迁移执行Active Record不知道如何撤消的操作,您可以使用reversible:

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
Run Code Online (Sandbox Code Playgroud)


小智 8

只需生成迁移:

rails g migration change_column_to_new_from_table_name
Run Code Online (Sandbox Code Playgroud)

像这样更新迁移:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end
Run Code Online (Sandbox Code Playgroud)

最后

rake db:migrate
Run Code Online (Sandbox Code Playgroud)


Seb*_*oll 6

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

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

/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
  ...
Run Code Online (Sandbox Code Playgroud)
    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
Run Code Online (Sandbox Code Playgroud)


小智 6

您可以change_column为此使用:

def change
  change_column :table_name, :column_name, :new_data_type
end
Run Code Online (Sandbox Code Playgroud)