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


我错误地命名了一个专栏 hased_password 代替 hashed_password

如何使用迁移重命名此列来更新数据库模式?


1282
2018-01-02 16:18


起源




答案:


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的更新

而, up 和 down 方法仍然适用。 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

谢谢, Luke && Turadg,提出这个话题。

然后就是 db:migrate 像往常一样,或者你去做你的生意。


Rails 4的更新

在创造一个 Migration 至于重命名列,Rails 4生成一个 change 方法代替 up 和 down 如上面的答案所述。生成的 change 方法如下:

$ > rails g migration ChangeColumnName

这将创建一个类似于此的迁移文件:

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

2084
2018-01-02 16:31



self.down应该 总是 与self.up相反,所以“如果你需要或做别的事情或什么都不做”并不是真的。只需执行:rename_column:table_name,:new_column,:old_column - Luke Griffiths
虽然恢复你所做的事情是正常的做法 self.up 我不会说 self.down “应该 总是 “取决于您的迁移环境。只是将”相反“放在一起可能不是”正确“的向下迁移。 - nowk
在Rails 3.1中,您可以替换 def self.up 和 def self.down 同 def change 它会知道如何回滚。 - Turadg
图拉格 - *它知道如何在大部分时间回滚。我找到了 change 方法不完全证明,所以倾向于使用 up 和 down 复杂迁移的方法。 - JellyFishBoy
重命名删除索引吗? - Sung Won Cho


在这种情况下,IMO可以更好地使用 rake db:rollback。然后编辑您的迁移并再次输入 rake db:migrate。但是,如果列中有数据,则不想丢失,请使用 rename_column


65
2018-01-03 00:55



即使在“一个团队”中,如果您的应用程序的多个实例正在运行,例如在不同的环境中或在多台计算机上等,管理已编辑的迁移是一个主要的痛苦。如果我,我只编辑迁移 只是 创造它并意识到它是错误的,并且还没有在其他任何地方运行它。 - Yetanotherjosh
之后我不得不重新启动服务器。 - Muhammad Hewedy
此技术仅应用于您的更改尚未与生产分支合并,而其他更改不依赖于数据持久性的情况。在大多数生产环境中,这不是首选方法。 - Collin Graves
从来没有做过这种事情。 - new2cpp
我想对我的团队说:'迁移是免费的'编辑已经发布的迁移的成本很高:我曾经花了几个小时来解决为什么我的代码在我意识到另一个团队成员之前没有工作的原因我已经回去编辑了一个我已经运行过的迁移。因此,不要编辑现有的迁移,使用新的迁移来更改模式,因为......“迁移是免费的!” (这不是严格意义上的,但它确实如此) - TerryS


http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

Available Transformations

rename_column(table_name, column_name, new_column_name):

重命名列但保留类型和内容。


26
2018-01-02 16:26



也可以看看 的文件 rename_column。 - Franklin Yu


如果该列已经填充了数据并且正在生产中,我建议采用一步一步的方法,以避免在等待迁移时停止生产。

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

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 在后台。

我意识到这涉及到一个过程,但我更愿意这样做,而不是生产迁移的问题。


24
2017-08-30 22:08



我喜欢这背后的想法,我会为你的repsonse +1,但是数据更新需要很长时间才能执行,因为它通过rails并一次执行一行。使用原始sql语句迁移将更快地执行以更新正确命名的列。例如,在第一个db迁移脚本中,添加重复的列名后, execute "Update table_name set correct_name_column_one = old_name_column_one" - Gui Weinmann
@ mr.ruh.roh ^完全同意,应该首先写一下。我编辑过来反映一个有效的sql语句。谢谢你的理智检查。 - Paul Pettengill
移动到新表和更新代码以使用新表之间的条目会发生什么?您是否可以留下潜在的未迁移数据? - Stefan Dorunga
虽然这是一个“安全”的答案,但我觉得它不完整。这里有很多人说不要这样做 - 为什么?持久化数据。这是有效的。实现目标的最不痛苦的方法可能是创建新字段,使用旧列中的数据填充它们,调整控制器。如果要删除旧列,则必须编辑视图。保留它们的成本是额外的数据库空间和控制器中的一些重复工作。因此权衡是明确的。 - Jerome


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

rails g migration ChangeHasedPasswordToHashedPassword

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

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

16
2017-12-03 11:45





来自API:

rename_column(table_name, column_name, new_column_name)

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


13
2018-02-18 11:15





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

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 Migrations


12
2018-02-14 10:38