Ruby-on-rails 运行 rake db:migrate 时,Rails 创建迁移以将列添加到表会导致错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13168450/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:57:50  来源:igfitidea点击:

Rails creating migration to add columns to table causes error when running rake db:migrate

ruby-on-railsrubyruby-on-rails-3migration

提问by Catfish

I have a model created called "users" and i created a new migration to add some columns to the users table. Now when i run rake db:migrate, I get the error below b/c it's trying to create the users table again

我创建了一个名为“users”的模型,我创建了一个新的迁移以将一些列添加到用户表中。现在,当我运行 rake db:migrate 时,我在 b/c 下面收到错误,它正在尝试再次创建用户表

$ rake db:migrate
==  DeviseCreateUsers: migrating ==============================================
-- create_table(:users)
rake aborted!
An error has occurred, all later migrations canceled:

Mysql::Error: Table 'users' already exists: CREATE TABLE `users`.....

Why is it trying to create the table again?

为什么它试图再次创建表?

Here's the command i used to create the new migration

这是我用来创建新迁移的命令

$ rails generate migration AddDetailsToUsers home_phone:decimal cell_phone:decimal work_phone:decimal birthday:date home_address:text work_address:text position:string company:string

The new migration looks like this:

新的迁移如下所示:

class AddDetailsToUsers < ActiveRecord::Migration
  def change
    add_column :users, :home_phone, :decimal
    add_column :users, :cell_phone, :decimal
    add_column :users, :work_phone, :decimal
    add_column :users, :birthday, :date
    add_column :users, :home_address, :text
    add_column :users, :work_address, :text
    add_column :users, :position, :string
    add_column :users, :company, :string
  end
end

EDIT

编辑

20120511224920_devise_create_users

20120511224920_devise_create_users

class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ## Database authenticatable
      t.string :email,              :null => false, :default => ""
      t.string :username,           :null => false, :default => ""
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Encryptable
      # t.string :password_salt

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, :default => 0 # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      ## Token authenticatable
      # t.string :authentication_token


      t.timestamps
    end

    add_index :users, :email,                :unique => true
    add_index :users, :reset_password_token, :unique => true
    # add_index :users, :confirmation_token,   :unique => true
    # add_index :users, :unlock_token,         :unique => true
    # add_index :users, :authentication_token, :unique => true
  end
end

20120619023856_add_name_to_users

20120619023856_add_name_to_users

class AddNameToUsers < ActiveRecord::Migration
  def change
    add_column :users, :first_name, :string
    add_column :users, :last_name, :string
  end
end

20121031174720_add_details_to_users.rb

20121031174720_add_details_to_users.rb

class AddDetailsToUsers < ActiveRecord::Migration
  def change
    add_column :users, :home_phone, :decimal
    add_column :users, :cell_phone, :decimal
    add_column :users, :work_phone, :decimal
    add_column :users, :birthday, :date
    add_column :users, :home_address, :text
    add_column :users, :work_address, :text
    add_column :users, :position, :string
    add_column :users, :company, :string
  end
end

采纳答案by omarvelous

Rails keeps track of the migrations in the "schema_migrations" table of your database. Unless there is an entry for "20120511224920", which is the Devise migration, it will attempt to run it again, which it appears to already exists.

Rails 在数据库的“schema_migrations”表中跟踪迁移。除非有“20120511224920”的条目,即设计迁移,否则它将尝试再次运行它,它似乎已经存在。

You can add that manually to the table if that is the case.

如果是这种情况,您可以手动将其添加到表中。

回答by GorrillaMcD

The error is saying that it's trying to run the original DeviseCreateUsers migration again and can't because the users table already exists.

错误是说它正在尝试再次运行原始的 DeviseCreateUsers 迁移并且不能,因为 users 表已经存在。

To fix this, you can run the down migration for DeviseCreateUsersand then run migrations as normal. You can do that with:

要解决此问题,您可以运行向下迁移DeviseCreateUsers,然后正常运行迁移。你可以这样做:

rake db:migrate:down VERSION=20121031XXXXXXXX
rake db:migrate

Where 20121031XXXXXXXXis the date stamp of the migration name. In other words, you'll have a migration named 20120410214815_devise_create_users.rband you copy the date stamp from the filename and paste it into the command. Here's the Rails Guide on Migrations for reference.

20121031XXXXXXXX迁移名称的日期戳在哪里。换句话说,您将有一个命名的迁移20120410214815_devise_create_users.rb,您从文件名复制日期戳并将其粘贴到命令中。这是 Rails 迁移指南,供参考

Edit:This is noted in the comments, but just a word of warning. Running the down migration for a table will lose any entries that table has. I assume you're running in development mode, so this shouldn't be a problem. If you're in production, you will need to take extra steps to backup the table data and reload it afterwards, otherwise you're going to have a bad day (or week maybe).

编辑:这是在评论中指出的,但只是一个警告。对表运行向下迁移将丢失该表具有的所有条目。我假设您在开发模式下运行,所以这应该不是问题。如果您在生产中,您将需要采取额外的步骤来备份表数据并在之后重新加载它,否则您将度过糟糕的一天(或一周)。

回答by Thanh

Can you try make a fresh database and then migrate it again:

您可以尝试创建一个新的数据库,然后再次迁移它:

rake db:drop:all
rake db:create:all
rake db:migrate

回答by Michael McGuire

So from what I have gathered from this:

所以从我从这里收集到的:

  • You already had a User model
  • You have a version of this in production
  • You ran a default rails generate devise:install
  • You then ran rails generate devise User
  • 你已经有一个 User 模型
  • 你在生产中有一个这个版本
  • 你运行了一个默认的 rails generate devise:install
  • 然后你运行 rails generate devise User

I am hoping that:

我希望:

  • You use source control
  • You check code in a lot
  • 您使用源代码管理
  • 你检查了很多代码

NOTE: If not, you are about to learn why you need to do so.

注意:如果没有,您将了解为什么需要这样做。

Revert your code to before you generated Devise

将您的代码恢复到生成设计之前

Hopefully, you can just create a new sandbox of a point right before generating Devise. If not, copy your project directory and do it by hand. The only other option is manually edit all the files that Devise generated.

希望您可以在生成 Devise 之前创建一个点的新沙箱。如果没有,请复制您的项目目录并手动完成。唯一的其他选项是手动编辑 Devise 生成的所有文件。

Rerun your Devise generation

重新运行你的设计一代

  • readd gem 'devise' to your Gemfile
  • rails generate devise:install
  • rails generate devise MODEL
  • 将 gem 'devise' 读到你的 Gemfile
  • rails 生成设计:安装
  • rails 生成设计模型

Make sure that model does not exist! If you don't you get into the problem you are currently having.

确保该模型不存在!如果你不这样做,你就会陷入当前遇到的问题。

Migrate current users from one model to the other

将当前用户从一种模型迁移到另一种模型

If you can generate a script to completely move authentication information from your old user model to the new, good for you. If you are using a different hashing algorithm from Devise for your current authentication, then you are going to either invalidate all of their passwords and require your users to create a new password using a confirmation code in their email OR you could migrate users as they log in. The first method is clean, complete, and rude. The second method is ugly, incomplete, and silent. Choose your method however you like.

如果您可以生成一个脚本来将身份验证信息从旧用户模型完全转移到新用户模型,那么对您有好处。如果您使用与 Devise 不同的散列算法进行当前的身份验证,那么您要么使他们的所有密码无效,并要求您的用户使用其电子邮件中的确认码创建一个新密码,要么您可以在用户登录时迁移他们in. 第一种方法干净、完整、粗鲁。第二种方法是丑陋的、不完整的、无声的。选择你喜欢的方法。

Edit: You could probably find a way to customize Devise to use your algorithm instead. That would probably be even better, but a little more work and fairly brittle.

编辑:您可能会找到一种方法来自定义设计以使用您的算法。那可能会更好,但需要更多的工作并且相当脆弱。

Another thing is that your authentication model should not be overloaded with account data. You should have a model that only handles authentication which has_a account data model that stores whatever you might want to track about accounts.

另一件事是您的身份验证模型不应被帐户数据过载。您应该有一个仅处理身份验证的模型,该模型具有帐户数据模型,该模型存储您可能想要跟踪的有关帐户的任何内容。

回答by vijikumar

use up and down methods. It will be useful for rollback and running specific migration file.

使用 up 和 down 方法。这对于回滚和运行特定的迁移文件非常有用。

Please follow the syntax..

请遵循语法..

  class AddDetailsToUsers < ActiveRecord::Migration
    def self.up
      add_column :users, :home_phone, :decimal
      add_column :users, :cell_phone, :decimal
      add_column :users, :work_phone, :decimal
      add_column :users, :birthday, :date
      add_column :users, :home_address, :text
      add_column :users, :work_address, :text
      add_column :users, :position, :string
      add_column :users, :company, :string
   end

   def self.down
      remove_column :users, :home_phone
      remove_column :users, :cell_phone
      remove_column :users, :work_phone
      remove_column :users, :birthday
      remove_column :users, :home_address
      remove_column :users, :work_address
      remove_column :users, :position
      remove_column :users, :company
   end
  end


    In this case please try to migrate using version number.

Like rake db:migrate:down VERSION=version number #version number is which version you wants to migrate.

比如 rake db:migrate:down VERSION=version number #version number 是你要迁移的版本。

回答by lutze

Check for some environmental variables that might be supplying an unexpected value for the version of your migration. I found an old questionon Stack Overflow (and forgive me if it is way out of date) where db:migratewas destroying the table, instead of applying an existing new migration.

检查一些可能为迁移版本提供意外值的环境变量。我在 Stack Overflow 上发现了一个老问题(如果它已经过时了,请原谅我)在哪里db:migrate销毁表,而不是应用现有的新迁移。

They eventually found that an environmental variable was causing db:migrateto run with a version parameter of "0" which is functionally equivalent to rake db:migrate:down

他们最终发现一个环境变量导致db:migrate以“0”的版本参数运行,这在功能上等同于rake db:migrate:down

Is it possible that your situation could be caused by the version being unexpectedly changed to include or match the previous migration DeviseCreateUsers?

您的情况是否可能是由于版本意外更改以包含或匹配先前的迁移而导致的DeviseCreateUsers

回答by Yanhao

I guess you ran rails generate devise usersometime which generated DeviseCreateUsers. If you have already created User model and users table, you can delete the generated migration file from db/migrate.

我猜你跑了rails generate devise user某个时候生成了DeviseCreateUsers. 如果您已经创建了 User 模型和 users 表,您可以从 db/migrate 中删除生成的迁移文件。

回答by Aayush Khandelwal

just try

你试一试

in the first file

在第一个文件中

create_table(:users), :force => true do |t|

this will override any other table

这将覆盖任何其他表

回答by Nikhil Nanjappa

According to what you said you used this command to create a new migration

根据您所说的,您使用此命令创建了一个新的迁移

$ rails generate migration AddDetailsToUsers home_phone:decimal cell_phone:decimal work_phone:decimal birthday:date home_address:text work_address:text position:string company:string

$ rails generate migration AddDetailsToUsers home_phone:decimal cell_phone:decimal work_phone:decimalbirthday:date home_address:text work_address:text position:string company:string

Im not sure if its just a typo but it should be "AddDetailsToUser" and not "Users". Just check again and we will be able to help you. This is for devise generated model. When you mention User, in db it looks for Users.

我不确定它是否只是一个错字,但它应该是“AddDetailsToUser”而不是“Users”。请再次检查,我们将能够为您提供帮助。这是用于设计生成的模型。当您提到用户时,它会在 db 中查找用户。

Ruby on Rails follow linguistic convention.table_name is Plural but model_name is Singular. You have to use model_name in the command you used.

Ruby on Rails 遵循语言约定。table_name 是复数,而 model_name 是单数。您必须在您使用的命令中使用 model_name。

If you want to use table_name then use this

如果你想使用 table_name 然后使用这个

rails g migration add_details_to_users home_phone:decimal......etc

rails g 迁移 add_details_to_users home_phone:decimal ......等

回答by Dorian

And if you need to do some dirty migrations manually:

如果您需要手动进行一些脏迁移:

class A < ActiveRecord::Migration
  def up
    add_column :images, :name
  end
end

A.new.migrate(:up)