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

How can I rename a database column in a Ruby on Rails migration?

提问人:user1994764 提问时间:1/3/2010 最后编辑:halferuser1994764 更新时间:12/6/2022 访问量:622134

问:

我错误地命名了一列而不是.hased_passwordhashed_password

如何更新数据库架构,使用迁移重命名此列?

ruby-on-rails ruby-on-rails-3 迁移 重命名 alter-table

评论


答:

28赞 James Manning 1/3/2010 #1

请参阅“活动记录迁移”文档中的“可用转换”部分。

rename_column(table_name, column_name, new_column_name):

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

评论

1赞 Franklin Yu 6/25/2017
另请参阅rename_column文档
2499赞 nowk 1/3/2010 #2
rename_column :table, :old_column, :new_column

为此,您可能需要创建单独的迁移。(随心所欲地重命名。FixColumnName

bin/rails 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,请使用:

虽然 和 方法仍然适用,但 Rails 3.1 接收到一个方法,该方法“知道如何迁移数据库并在迁移回滚时将其反转,而无需编写单独的 down 方法”。updownchange

有关详细信息,请参阅“活动记录迁移”。

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:

在创建用于重命名列时,Rails 4 会生成一个方法,而不是上一节中提到的 and。生成的方法为:Migrationchangeupdownchange

$ > rails g migration ChangeColumnName

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

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

评论

31赞 Luke Griffiths 8/29/2011
self.down 应该始终是 self.up 的反面,因此不建议“如果你需要或做其他事情或什么都不做”。只需执行:rename_column:table_name、:new_column、:old_column
3赞 nowk 8/30/2011
虽然恢复你所做的事情是正常的做法,但我不会说“应该总是相反的”。取决于迁移的上下文。仅仅把“相反”放在一起可能不是“正确”的向下迁移。self.upself.down
25赞 Turadg 9/10/2011
在 Rails 3.1 中,你可以替换 and,它会知道如何回滚。def self.updef self.downdef change
3赞 JellyFishBoy 10/19/2014
Turadg - *它会知道如何在大多数时候回滚。我发现该方法不是完全证明的,因此倾向于使用 和 方法进行复杂的迁移。changeupdown
8赞 mc9 4/12/2015
重命名会删除索引吗?
72赞 elf.xf 1/3/2010 #3

在我看来,在这种情况下,最好使用 ,然后编辑您的迁移并再次运行 .rake db:rollbackrake db:migrate

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

评论

44赞 Yetanotherjosh 12/9/2013
即使在“一个人的团队”中,如果您有多个应用程序实例在运行,例如在不同的环境或多台计算机上等,管理编辑的迁移也是一个很大的痛苦。只有当我刚刚创建迁移并意识到它是错误的,并且还没有在其他任何地方运行它时,我才会编辑它。
1赞 Muhammad Hewedy 9/7/2015
在那之后,我不得不重新启动服务器。
12赞 Collin Graves 1/4/2017
此技术应仅在更改尚未与生产分支合并,并且其他更改不依赖于数据持久性的情况下使用。在大多数生产环境中,这不是首选方法。
6赞 new2cpp 2/23/2017
永远不要做这种事情。
7赞 TerryS 9/4/2017
我喜欢对我的团队说:“迁移是免费的” 编辑已发布到野外的迁移的成本很高:我曾经花了几个小时弄清楚为什么我的代码不起作用,然后我意识到另一个团队成员已经回去编辑了我已经运行的迁移。因此,不要编辑现有迁移,而应使用新的迁移来更改架构,因为......“迁移是免费的!(这并不完全正确,但它说明了这一点)
17赞 super_p 2/18/2011 #4

从 API:

rename_column(table_name, column_name, new_column_name)

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

9赞 Steven Garcia 1/31/2012 #5

作为替代选择,如果您不了解迁移的想法,那么 ActiveRecord 有一个引人注目的 gem,它将自动为您处理名称更改,即 Datamapper 样式。您所要做的就是更改模型中的列名,并确保将 model.rb 和 viola 放在底部!数据库会即时更新。Model.auto_upgrade!

查看 https://github.com/DAddYE/mini_record

注意:您需要对 db/schema.rb 进行核弹以防止冲突。

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

7赞 dirtydexter 7/26/2013 #6

如果当前数据对您来说并不重要,您可以使用以下方法删除原始迁移:

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

如果不带引号,则对原始迁移进行更改,并通过以下方式再次运行向上迁移:

rake db:migrate
37赞 Paul Pettengill 8/31/2013 #7

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

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

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赞 Gui LeFlea 9/10/2013
我喜欢这背后的想法,我会+1你的回复,但数据更新需要很长时间才能执行,因为它通过轨道并一次做一行。使用原始 sql 语句更新正确命名的列,迁移的执行速度会快得多。例如,在第一个数据库迁移脚本中,添加重复的列名后,execute "Update table_name set correct_name_column_one = old_name_column_one"
1赞 Paul Pettengill 9/14/2013
@mr.ruh.roh ^ 完全同意,应该首先写。我已经编辑以反映一个有效的 sql 语句。感谢您的健全性检查。
4赞 Stefan Dorunga 10/8/2014
在移动到新表和更新代码以使用新表之间的条目会发生什么情况?难道您没有剩余的未迁移数据吗?
1赞 Jerome 7/29/2017
虽然这是一个“安全”的答案,但我觉得它不完整。这里的很多人说不要这样做——为什么?数据的持久性。这是有道理的。实现目标最不痛苦的方法可能是创建新字段,用旧列中的数据填充它们,调整控制器。如果要删除旧列,则必须编辑视图。保留它们的代价是额外的数据库空间和控制器中的一些重复工作。因此,权衡是明确的。
8赞 Abram 9/10/2013 #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
12赞 sunil 12/4/2013 #9

如果您的代码未与其他代码共享,那么最好的选择是在迁移和 .就是这样rake db:rollbackrake db:migrate

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

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

就是这样。

评论

0赞 danielricecodes 3/14/2019
rake db:rollback是一个很好的建议。但就像你说的,只有在迁移尚未推进的情况下。
12赞 uma 2/14/2014 #10

某些版本的 Ruby on Rails 支持 / 方法进行迁移,如果迁移中有 / 方法,则:updownupdown

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 迁移

7赞 jon snow 3/24/2014 #11

只需创建一个新的迁移,并在一个块中使用如下。rename_column

rename_column :your_table_name, :hased_password, :hashed_password
5赞 Sumit Munot 7/14/2014 #12

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

我们可以手动编辑迁移,如下所示:

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

  • 更新到hased_passwordhashed_password

  • 运行以下命令

    $> rake db:migrate:down VERSION=xxxxxxxxx
    

然后,它将删除您的迁移:

$> rake db:migrate:up VERSION=xxxxxxxxx

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

评论

0赞 Tejas Patel 7/23/2015
这将是不安全的,因为您可能会丢失数据 - 如果该列已经处于活动状态。但可以用于新的列和/或表。
21赞 Shoaib Malik 12/3/2014 #13

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

rails g migration ChangeHasedPasswordToHashedPassword

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

class ChangeOldColumnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end
8赞 Hardik Hardiya 1/20/2015 #14

对于 Ruby on Rails 4:

def change
    rename_column :table_name, :column_name_old, :column_name_new
end

评论

0赞 stevec 2/18/2022
万一它节省了有人查找它,是复数。例如:studentstable_name
2赞 Sarwan Kumar 1/29/2015 #15

有两种方法可以执行此操作:

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

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
    
  2. 对于此类型,它在以下情况下运行 up 方法,并在以下情况下运行 down 方法:rake db:migraterake 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赞 rinold simon 6/3/2015 #16

打开 Ruby on Rails 控制台并输入:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column
8赞 vipin 12/28/2015 #17

生成迁移文件:

rails g migration FixName

这创建了 .db/migrate/xxxxxxxxxx.rb

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

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
4赞 vipin 1/26/2016 #18

生成 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
4赞 Prabhakar 3/23/2016 #19
$:  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
1赞 Hieu Pham 5/21/2016 #20

is 的近亲,用于更改现有表。它的使用方式与块类似,但屈服于块的对象知道更多技巧。例如:create_tablechange_tablecreate_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

如果我们将它与 alter 方法一起使用,例如:删除/添加索引/删除索引/添加列,这种方式会更有效。我们可以做这样的事情:

重命名

t.rename :old_column_name, :new_column_name

添加列

t.string :new_column

删除列

t.remove :removing_column

索引列

t.index :indexing_column

评论

0赞 the Tin Man 2/4/2022
请不要使用“已编辑”或“更新”类型的标签。相反,将更改合并,就好像它一直存在一样。如果我们需要知道发生了什么更改,我们可以查看编辑日志。
5赞 Maddie 12/24/2016 #21

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

打开刚刚生成的迁移文件,在方法中添加以下行(介于 和 之间):def changeend

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

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

检查您的,看看数据库中的名称是否真的发生了变化!schema.db

希望这对:)有所帮助

5赞 Apoorv 6/9/2017 #22
 def change
    rename_column :table_name, :old_column_name, :new_column_name
  end

评论

0赞 the Tin Man 2/4/2022
如果您解释为什么这是首选解决方案并解释其工作原理,则会更有帮助。我们想要教育,而不仅仅是提供代码。
0赞 Ratnam Yadav 10/5/2017 #23

只需使用以下命令生成迁移:

rails g migration rename_hased_password

之后,编辑迁移并在方法中添加以下行:change

rename_column :table, :hased_password, :hashed_password

这应该可以解决问题。

-1赞 Prasanth_Rubyist 12/20/2017 #24

Rails 5 迁移更改

例如:

rails g 模型 学生student_name:字符串 age:integer

如果要将student_name列更改为名称

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

您可以执行以下步骤

rails d 模型 学生student_name:字符串 age:integer

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

rails g 模型 学生姓名:字符串 age:integer

如果您迁移了(rails db:migrate),请通过以下选项更改列名

rails g 迁移 RemoveStudentNameFromStudent student_name:string

rails g 迁移 AddNameToStudent name:string

评论

0赞 BenKoshy 1/14/2019
不应该是:(学生是复数)吗?rails g migration RemoveStudentNameFromStudentS student_name:string
1赞 BenKoshy 1/14/2019
这也是危险的:该列不会重命名,而是完全删除,然后重新添加。数据会发生什么变化?这可能不是用户想要的。
2赞 tomb 9/6/2018 #25

我在 rails 5.2 上,并试图重命名 devise User 上的列。

该位对我有用,但单数抛出“找不到用户表”错误。复数对我有用。rename_column:table_name

rails g RenameAgentinUser

然后将迁移文件更改为:

rename_column :users, :agent?, :agent

哪里:agent?是旧列名。

6赞 BenKoshy 1/14/2019 #26

让我们接吻吧。只需三个简单的步骤。以下是 Rails 5.2 的工作原理。

1 .创建迁移

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- 这样一来,代码库的维护者就非常清楚了。(使用复数形式表示表名)。

2. 编辑迁移

# I prefer to explicitly write the上下andmethods.

# ./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

你开始比赛了!

14赞 Promise Preston 10/28/2020 #27

在使用 PostgreSQL 数据库开发 Rails 6 应用程序时,我遇到了这个挑战。

这是我修复它的方法:

在我的情况下,是“产品”,是“SKU”,是“ProductNumber”。table_nameold_columnnew_column

  1. 创建一个迁移文件,该文件将包含用于重命名列的命令:

     rails generate migration RenameSKUToProductNumberInProducts
    
  2. 在以下位置打开迁移文件:db/migrate directory

     db/migrate/20201028082344_rename_sku_to_product_number_in_products.rb
    
  3. 添加用于重命名列的命令:

     class RenameSkuToProductNumberInProducts < ActiveRecord::Migration[6.0]
       def change
         # rename_column :table_name, :old_column, :new_column
         rename_column :products, :sku, :product_number
       end
     end
    
  4. 保存,然后运行迁移命令:

     rails db:migrate
    

现在,您可以通过查看架构文件来确认列的重命名:

    db/schema.rb

如果您对列的重命名不满意,可以随时回滚:

    rails db:rollback

注意:努力在调用列名的所有位置将列名修改为新名称。

1赞 Sachin Singh 4/23/2021 #28

您可以编写迁移,运行以下命令来更新列名:

rename_column :your_table_name, :hased_password, :hashed_password

此外,请确保使用新列名更新代码中旧列名的任何用法。

0赞 Sara Lins 6/16/2021 #29

rails g migration migrationName

因此,转到生成的迁移并添加:

rename_column :table, :old_column, :new_column

到方法

0赞 Saman 9/4/2021 #30

首先,你需要运行

rails g migration create_new_column_in_tablename new_column:datatype
rails g migration remove_column_in_tablename old_column:datatype

然后你需要检查db / migration 您可以在 NEM 迁移中查看详细信息,如果所有详细信息都正确,则需要运行:

rails db:migrate

评论

0赞 Lam Phan 9/6/2021
您是否需要将现有数据从 old_column 迁移到 new_column?
0赞 Saman 9/7/2021
不,如果你只想重命名它,你不需要。
3赞 Ashish Darji 12/24/2021 #31

在控制台中:

rails generate migration newMigration

在 newMigration 文件中:

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

评论

0赞 Community 12/24/2021
您的答案可以通过额外的支持信息得到改进。请编辑以添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以在帮助中心找到有关如何写出好答案的更多信息。
0赞 rnewed_user 11/8/2022 #32

可能比重命名列、创建新列并复制内容更好:

通过这种方式,我们可以将内容保存在旧列中

这可能是这一代人:

rails generate migration add_birthdate_to_User birthdate:string

这可能是迁移:

class AddBirthdateToUser < ActiveRecord::Migration[7.0]
  def change
    add_column :user, :birthdate, :json, default: '[]', null: false

    reversible do |dir|
      dir.up do
        User.update_all('birthdate=birtdate') # rubocop:disable Rails/SkipsModelValidations
      end
    end
  end
end

之后,您必须删除错误的列“Birtdate”

class RemoveBirthdateFromUser < ActiveRecord::Migration[7.0]
  def change
    remove_column :User, :Birtdate, :json
  end
end