在Rails迁移中将列添加到现有表


340

我有一个需要一:email列的Users模型(我忘记在初始支架中添加该列)。

我打开了迁移文件,然后添加t.string :email,执行并rake db:migrate得到了一个NoMethodError。然后我添加了线

add_column :users, :email, :string

rake db:migrate一次NoMethodError。我在这里错过了一步吗?

编辑:这是迁移文件。

class CreateUsers < ActiveRecord::Migration  
  def self.up  
    add_column :users, :email, :string  
    create_table :users do |t|  
      t.string :username  
      t.string :email  
      t.string :crypted_password  
      t.string :password_salt  
      t.string :persistence_token  

      t.timestamps  
    end  
  end  

  def self.down  
    drop_table :users  
  end  
end

Answers:


573

如果已经运行了原始迁移(在编辑之前),则需要生成一个新的迁移(rails generate migration add_email_to_users email:string将完成此操作)。它将创建一个包含以下行的迁移文件: add_column :users, email, string 然后执行a rake db:migrate,它将运行新迁移,并创建新列。

如果您尚未运行原始迁移,则可以像尝试进行的那样对其进行编辑。您的迁移代码几乎是完美的:您只需要add_column完全删除该行即可(该代码正试图在创建表之前向表中添加列,并且t.string :email无论如何您的表创建代码都已进行了更新)。


6
为了清楚起见,我们使用复数吗?所以add_email_to_users不是add_email_to_user吗?
Purplejacket 2013年

9
正确。Rails中的表名始终为复数形式(以匹配数据库约定)。
camdez 2014年

2
您也可以将其rails db:migrate用于最后一步。
迪伦范德伯格

是否可以在表中的特定位置上创建新列。例如,如果我想在现有“电子邮件”字段之后立即创建新字段“状态”?
neeraj

2
@neeraj现在您可能已经有了答案,但是对于其他寻求者,是的,您可以例如t.string :column_x, limit: 10, after: :column_y(至少适用于Rails 4)
244an

123

在Rails控制台上使用此命令

rails generate migration add_fieldname_to_tablename fieldname:string

rake db:migrate

运行此迁移


57

有时rails generate migration add_email_to_users email:string会产生这样的迁移

class AddEmailToUsers < ActiveRecord::Migration[5.0]
  def change
  end
end

在这种情况下,您必须手动将add_column转到change

class AddEmailToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :email, :string
  end
end

然后跑 rake db:migrate


1)应该在终端rails generate migration add_email_to_users email:string之后bundle exec rails c还是在终端内部运行?2)执行查询后,生成的文件将放置在哪里?
sofs1

28

你也可以

rake db:rollback

如果尚未向表中添加任何数据。然后通过向其添加电子邮件列来编辑迁移文件,然后调用

rake db:migrate

如果您的系统中已安装Rails 3.1及更高版本,则此方法将起作用。

更简单的方法是更改​​,让迁移文件中的更改保持原样。采用

$rake db:migrate:redo

这将回滚上一次迁移并再次迁移。


21

要添加列,我只需要遵循以下步骤:

  1. rails generate migration add_fieldname_to_tablename fieldname:string

    另类

    rails generate migration addFieldnameToTablename

    生成迁移后,请编辑迁移并定义要添加该列的所有属性。

    注意:Rails中的表名称始终是复数形式(以匹配数据库约定)。使用前面提到的步骤之一的示例-

    rails generate migration addEmailToUsers

  2. rake db:migrate

要么

  1. 您可以从中更改架构,db/schema.rb在SQL查询中添加所需的列。
  2. 运行以下命令: rake db:schema:load

    警告/注意

    请记住,rake db:schema:load自动运行会擦除表中的所有数据。


我这样做了,但是它没有重做“脚手架”并添加新列。我该如何“自动地”做到这一点?
John Wooten

@John Wooten,您可能想删除脚手架,然后再次进行检查。也删除相应的迁移。
Afolabi Olaoluwa Akinwumi

补充说明:在不更改迁移的情况下更改架构可能会与其他维护该应用程序的开发人员产生问题。
BKSpurgeon

3

完成此操作后,我没有摆弄原始的迁移,而是创建了一个新的迁移,仅在up部分中有add列,在down部分中有drop列。

如果您之间进行向下迁移,则可以更改原始文件并重新运行它,但是在这种情况下,我认为这是无法正常进行的迁移。

如当前发布的那样,您要添加列,然后创建表。

如果您更改顺序,则可能会起作用。或者,在修改现有迁移时,只需将其添加到创建表中,而不用做一个单独的添加列。


1

force: true如果您的表格已经存在,也可以使用强制在表格中使用表格列。

例如

ActiveRecord::Schema.define(version: 20080906171750) do
  create_table "authors", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end


0

您可以通过以下方式回滚上一次迁移

rake db:rollback STEP=1

或回滚此特定迁移

rake db:migrate:down VERSION=<YYYYMMDDHHMMSS>

并编辑文件,然后rake db:mirgate再次运行。



0

您还可以使用列之前或之后将列添加到特定位置,例如:

rails generate migration add_dob_to_customer dob:date

迁移文件将生成以下代码,但:: email除外。您需要在以下位置添加::email或之前::email

class AddDobToCustomer < ActiveRecord::Migration[5.2]
  def change
    add_column :customers, :dob, :date, after: :email
  end
end
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.