如何在Ruby on Rails迁移中重命名数据库列?


Answers:


2308
rename_column :table, :old_column, :new_column

您可能需要创建一个单独的迁移来执行此操作。(请重命名FixColumnName。):

script/generate migration FixColumnName
# creates  db/migrate/xxxxxxxxxx_fix_column_name.rb

然后编辑迁移以执行您的意愿:

# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
  def self.up
    rename_column :table_name, :old_column, :new_column
  end

  def self.down
    # rename back if you need or do something else or do nothing
  end
end

对于Rails 3.1,请使用:

虽然updown方法仍然适用,但是Rails 3.1接收到的change方法“知道如何迁移数据库,并且在回滚迁移时无需编写单独的down方法就可以反向数据库”。

有关更多信息,请参见“ 活动记录迁移 ”。

rails g migration FixColumnName

class FixColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

如果您碰巧有一整列要重命名的列,或者需要一遍又一遍地重复表名的事情:

rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...

您可以change_table用来使事情保持整洁:

class FixColumnNames < ActiveRecord::Migration
  def change
    change_table :table_name do |t|
      t.rename :old_column1, :new_column1
      t.rename :old_column2, :new_column2
      ...
    end
  end
end

然后db:migrate像往常一样或随便你去做生意。


对于Rails 4:

在创建Migration用于重命名列的时,Rails 4会生成一个change方法代替上述部分中提到的updown。生成的change方法是:

$ > rails g migration ChangeColumnName

这将创建一个类似于以下内容的迁移文件:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

24
self.down应该始终与self.up相反,因此,实际上不建议“如果您需要或做其他事情或什么都不做”。只需做:rename_column:table_name,:new_column,:old_column
卢克·格里菲思

3
恢复您所做的正常操作是正常的,但self.up我不会说self.down“应该总是相反”。具体取决于您的迁移环境。仅仅把“对立”放在首位可能不是“正确”的向下迁移。
nowk 2011年

23
在Rails 3.1中,您可以替换def self.updef self.downdef change它将知道如何回滚。
Turadg 2011年

2
Turadg-*大多数时间都会知道如何回滚。我发现该change方法不是完全证明,因此倾向于使用updown方法进行复杂的迁移。
JellyFishBoy 2014年

6
重命名会删除索引吗?
宋祖

68

我认为,在这种情况下,最好使用rake db:rollback,然后编辑迁移并再次运行rake db:migrate

但是,如果您不想丢失该列中的数据,请使用rename_column


34
即使是“一个团队”,如果您有多个应用程序实例在不同的环境中或在多台计算机等上运行,那么管理已编辑的迁移也是一个很大的难题。如果创建迁移并意识到它是错误的,并且还没有在其他任何地方运行它,那么我只会编辑迁移。
Yetanotherjosh 2013年

1
之后,我不得不重新启动服务器。
Muhammad Hewedy 2015年

7
仅当您的更改尚未与生产分支合并并且其他更改不依赖于数据持久性时,才应使用此技术。在大多数生产环境中,这都不是首选方法。
Collin Graves,

4
永远不会做这种事情。
new2cpp

4
我想对我的团队说:“迁移是免费的”编辑已发布到野外的迁移的成本很高:我曾经花了几个小时弄清楚为什么我的代码无法正常工作,然后才意识到另一个团队成员回去编辑了我已经运行的迁移。因此,不要编辑现有的迁移,而要使用新的迁移来更改架构,因为……“迁移是免费的!” (严格意义上并非如此,但这是正确的)
TerryS

31

如果该列中已经填充了数据并且已经投入生产,那么我建议您采用逐步方法,以避免在等待迁移时停产。

首先,我将创建一个数据库迁移,以添加具有新名称的列,并使用旧列名称中的值填充它们。

class AddCorrectColumnNames < ActiveRecord::Migration
  def up
    add_column :table, :correct_name_column_one, :string
    add_column :table, :correct_name_column_two, :string

    puts 'Updating correctly named columns'
    execute "UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two"
    end
  end

  def down
    remove_column :table, :correct_name_column_one
    remove_column :table, :correct_name_column_two
  end
end

然后,我只提交该更改,然后将更改投入生产。

git commit -m 'adding columns with correct name'

然后,一旦将提交推送到生产中,我就可以运行。

Production $ bundle exec rake db:migrate

然后,我将所有引用旧列名的视图/控制器更新为新列名。运行我的测试套件,然后提交那些更改。(确保它在本地工作并首先通过所有测试之后!)

git commit -m 'using correct column name instead of old stinky bad column name'

然后,我将把承诺投入生产。

此时,您可以删除原始列,而不必担心与迁移本身相关的任何停机时间。

class RemoveBadColumnNames < ActiveRecord::Migration
  def up
    remove_column :table, :old_name_column_one
    remove_column :table, :old_name_column_two
  end

  def down
    add_column :table, :old_name_column_one, :string
    add_column :table, :old_name_column_two, :string
  end
end

然后将最新的迁移推送到生产环境并bundle exec rake db:migrate在后台运行。

我意识到这更多地涉及到流程,但是我宁愿这样做,也不愿与我的产品迁移有关。


2
我喜欢这种想法,我会为您的回复+1,但是数据更新将花费很长的时间,因为它要经过轨道并一次执行一行。迁移将使用原始sql语句执行得更快,以更新正确命名的列。例如,在第一个数据库迁移脚本中,添加重复的列名称后, execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann 2013年

1
@ mr.ruh.roh ^完全同意,应该首先写出来。我进行了编辑,以反映单个有效的sql语句。感谢您的健全性检查。
Paul Pettengill

2
在移至新表和更新代码以使用新表之间的条目将如何处理?您是否可以保留未迁移的潜在数据?
Stefan Dorunga 2014年

1
尽管这是一个“安全”的答案,但我认为它并不完整。这里许多人说不这样做-为什么?数据的持久性。那是有效的。实现目标的最简单的方法可能是创建新字段,并使用旧列中的数据填充它们,并调整控制器。如果要删除旧列,则肯定必须编辑视图。保留它们的成本是额外的数据库空间以及控制器中的某些重复工作。因此,权衡是显而易见的。
杰罗姆


18

运行以下命令以创建迁移文件:

rails g migration ChangeHasedPasswordToHashedPassword

然后在文件db/migrate夹中生成的文件中,编写rename_column如下:

class ChangeOldCoulmnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end

14

从API:

rename_column(table_name, column_name, new_column_name)

它重命名列,但保持类型和内容不变。


12

某些版本的Ruby on Rails支持向上/向下方法进行迁移,如果您在迁移中具有向上/向下方法,则:

def up
    rename_column :table_name, :column_old_name, :column_new_name
end

def down
    rename_column :table_name, :column_new_name, :column_old_name
end

如果您change的迁移中包含该方法,则:

def change
    rename_column :table_name, :column_old_name, :column_new_name
end

有关更多信息,您可以移动:Ruby on Rails-迁移Active Record迁移


11

如果您的代码未与其他人共享,那么最好的选择是rake db:rollback 在迁移和中进行修改rake db:migrate。而已

您可以编写另一个迁移来重命名该列

 def change
    rename_column :table_name, :old_name, :new_name
  end

而已。


rake db:rollback是一个很好的建议。但是就像您说的那样,只有在尚未推动迁移的情况下。
danielricecodes,

9

作为一种替代选择,如果您不喜欢迁移的想法,那么ActiveRecord有一个引人注目的瑰宝,它将为您自动处理名称更改,即Datamapper样式。您要做的就是更改模型中的列名(并确保将Model.auto_upgrade!放在model.rb的底部)和中提琴!数据库是动态更新的。

https://github.com/DAddYE/mini_record

注意:您需要删除db / schema.rb以防止冲突

仍处于测试阶段,显然并不适合所有人,但仍然是一个令人信服的选择(我目前正在两个非平凡的生产应用程序中使用它,都没有问题)


8

如果需要切换列名,则需要创建一个占位符,以避免重复的列名错误。这是一个例子:

class SwitchColumns < ActiveRecord::Migration
  def change
    rename_column :column_name, :x, :holder
    rename_column :column_name, :y, :x
    rename_column :column_name, :holder, :y
  end
end

7

如果当前数据对您而言不重要,则可以使用以下命令删除原始迁移:

rake db:migrate:down VERSION='YOUR MIGRATION FILE VERSION HERE'

如果不带引号,请在原始迁移中进行更改,然后通过以下方式再次运行向上迁移:

rake db:migrate

6

只需创建一个新的迁移,然后rename_column按如下所示使用即可。

rename_column :your_table_name, :hased_password, :hashed_password


5

我们可以手动使用以下方法:

我们可以像这样手动编辑迁移:

  • 打开 app/db/migrate/xxxxxxxxx_migration_file.rb

  • 更新hased_passwordhashed_password

  • 运行以下命令

    $> rake db:migrate:down VERSION=xxxxxxxxx

然后它将删除您的迁移:

$> rake db:migrate:up VERSION=xxxxxxxxx

它将使用更新的更改添加您的迁移。


如果您可能会丢失数据,那么这将是不安全的-如果该列已经存在。但可以用于新的列和/或表。
2015年

5

生成迁移文件:

rails g migration FixName

#创建db / migrate / xxxxxxxxxx.rb

编辑迁移以按照您的意愿进行。

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

5

运行rails g migration ChangesNameInUsers(或任何您想命名的名称)

打开刚刚生成的迁移文件,然后在方法中(在def change和之间end)添加以下行:

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

保存文件,然后rake db:migrate在控制台中运行

请检查您schema.db的名称,以查看数据库中的名称实际上是否已更改!

希望这可以帮助 :)


5

让我们一下。它只需要三个简单的步骤。以下是Rails 5.2的工作

1。创建迁移

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName-这样一来,以后的代码维护者就很清楚了。(表名称使用复数形式)。

2.编辑迁移

# I prefer to explicitly write the向上and向下methods.

# ./db/migrate/20190114045137_rename_name_to_full_name_in_students.rb

class RenameNameToFullNameInStudents < ActiveRecord::Migration[5.2]
  def up
    # rename_column :table_name, :old_column, :new_column
    rename_column :students, :name, :full_name
  end

  def down
            # Note that the columns are reversed
    rename_column :students, :full_name, :name
  end
end

3.运行您的迁移

rake db:migrate

您将参加比赛!


4
$:  rails g migration RenameHashedPasswordColumn
invoke  active_record
      create    db/migrate/20160323054656_rename_hashed_password_column.rb

打开该迁移文件,然后按如下所示修改该文件(输入原始文件table_name

class  RenameHashedPasswordColumn < ActiveRecord::Migration
  def change
    rename_column :table_name, :hased_password, :hashed_password
  end
end

4
 def change
    rename_column :table_name, :old_column_name, :new_column_name
  end

3

生成Ruby on Rails迁移

$:> rails g migration Fixcolumnname

在迁移文件(XXXXXfixcolumnname.rb)中插入代码

class Fixcolumnname < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

2

打开Ruby on Rails控制台,然后输入:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column

2

您有两种方法可以做到这一点:

  1. 在这种类型的回滚时,它将自动运行其反向代码。

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. 对于这种类型,它将在以下情况下运行up方法,rake db:migrate并在以下情况下运行down方法rake db:rollback

    def self.up
      rename_column :table_name, :old_column_name, :new_column_name
    end
    
    def self.down
      rename_column :table_name,:new_column_name,:old_column_name
    end

2

我正在使用5.2,并且尝试重命名devise用户上的列。

rename_column位对我有用,但单数:table_name引发了“找不到用户表”错误。复数为我工作。

rails g RenameAgentinUser

然后将迁移文件更改为此:

rename_column :users, :agent?, :agent

哪里:agent?是旧的列名称。


0

更新 -create_table的近亲是change_table,用于更改现有表。它以与create_table相似的方式使用,但屈服于该块的对象知道更多的技巧。例如:

class ChangeBadColumnNames < ActiveRecord::Migration
  def change
    change_table :your_table_name do |t|
      t.rename :old_column_name, :new_column_name
    end
  end
end

如果我们使用其他更改方法,例如:remove / add index / remove index / add column,这种方法会更有效,例如,我们可以进一步做类似的事情:

# Rename
t.rename :old_column_name, :new_column_name
# Add column
t.string :new_column
# Remove column
t.remove :removing_column
# Index column
t.index :indexing_column
#...

0

只需使用命令生成迁移

rails g migration rename_hased_password

在编辑迁移之后,在更改方法中添加以下行

rename_column :table, :hased_password, :hashed_password

这应该可以解决问题。


0

Rails 5迁移变更

例如:

rails g model学生student_name:字符串年龄:整数

如果您想将student_name列更改为名称

注意:-如果不运行rails db:migrate

您可以执行以下步骤

rails d model学生student_name:字符串年龄:整数

这将删除生成的迁移文件,现在您可以更正列名

型号:学生姓名:字符串年龄:整数

如果要迁移(rails db:migrate),请使用以下选项来更改列名

Rails g迁移RemoveStudentNameFromStudent学生名称:字符串

rails g migration AddNameToStudent名称:字符串


不应该是:(rails g migration RemoveStudentNameFromStudentS student_name:string学生人数众多)吗?
BKSpurgeon

这也很危险:该列未重命名,而是被完全删除然后重新读取。数据将如何处理?这可能不是用户想要的。
BKSpurgeon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.