在运行rake db:migrate时,创建迁移以向表添加列的Rails会导致错误

时间:2012-10-31 22:37:17

标签: ruby-on-rails ruby ruby-on-rails-3 migration

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

$ 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`.....

为什么要再次创建表格?

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

$ 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

新迁移如下所示:

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

修改

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

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

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

10 个答案:

答案 0 :(得分:11)

Rails跟踪&#34; schema_migrations&#34;中的迁移。数据库表。除非有&#34; 20120511224920&#34;的条目,即Devise迁移,它将再次尝试运行它,它似乎已经存在。

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

答案 1 :(得分:6)

该错误表明它正在尝试再次运行原始DeviseCreateUsers迁移,但因为users表已经存在而无法运行。

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

来做到这一点
rake db:migrate:down VERSION=20121031XXXXXXXX
rake db:migrate

其中20121031XXXXXXXX是迁移名称的日期戳。换句话说,您将进行名为20120410214815_devise_create_users.rb的迁移,并从文件名中复制日期戳并将其粘贴到命令中。 Here's the Rails Guide on Migrations for reference

编辑:这在评论中有所说明,但只是警告。对表执行向下迁移将丢失表所具有的任何条目。我假设你在开发模式下运行,所以这应该不是问题。如果你正在制作中,你将需要采取额外的步骤来备份表数据并在之后重新加载它,否则你将会有糟糕的一天(或者可能是一周)。

答案 2 :(得分:5)

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

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

答案 3 :(得分:2)

从我从中收集到的内容:

  • 您已拥有用户模型
  • 您正在制作此版本
  • 您运行了默认的rails generate devise:install
  • 然后你运行了rails generate devise User

我希望:

  • 您使用源代码管理
  • 您经常检查代码

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

在生成Devise之前将代码还原为

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

重新运行你的Devise一代

  • 将宝石'设计'读到您的Gemfile
  • rails generate devise:install
  • rails generate devise MODEL

确保模型不存在!如果你不这样做,你会遇到你目前遇到的问题。

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

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

编辑:您可能会找到一种方法来自定义Devise以使用您的算法。这可能会更好,但更多的工作和相当脆弱。

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

答案 4 :(得分:2)

使用上下方法。它对于回滚和运行特定的迁移文件很有用。

请遵循语法..

  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.

与rake db:migrate:down相似VERSION =版本号#version number是您要迁移的版本。

答案 5 :(得分:1)

我猜你有时会rails generate devise user生成DeviseCreateUsers。如果您已创建用户模型和用户表,则可以从db / migrate。

中删除生成的迁移文件

答案 6 :(得分:1)

检查可能为迁移版本提供意外值的一些环境变量。我在Stack Overflow上找到an old question(并且如果它已过时,请原谅我)db:migrate正在销毁表,而不是应用现有的新迁移。

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

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

答案 7 :(得分:0)

试试

第一个文件中的

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

这将覆盖任何其他表

答案 8 :(得分:0)

根据您的说法,您使用此命令创建新的迁移

$ rails生成迁移AddDetailsToUsers home_phone:decimal cell_phone:decimal work_phone:decimal birthday:date home_address:text work_address:text position:string company:string

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

Ruby on Rails遵循语言约定.table_name是Plural,但model_name是Singular。您必须在您使用的命令中使用model_name。

如果您想使用table_name,请使用此

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

答案 9 :(得分:0)

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

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

A.new.migrate(:up)