2012-10-31 32 views
20

我创建了一个名为“users”的模型,并且我创建了一个新的迁移,将一些列添加到users表中。现在,当我运行耙分贝:迁移,我得到下面的二/三它试图创建用户表再次创建迁移以添加列到表的Rails导致运行rake数据库时出错:迁移

$ 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 
+0

从输出看起来好像在DeviseCreateUsers期间发生错误,而不是在您的新迁移中。您是否有另一个(旧的)迁移已经创建了Users表? – fwalch

+0

是的,我愿意。但我认为我应该能够像我一样添加新的迁移并运行rake数据库:迁移应该只运行尚未运行的迁移。 – Catfish

+0

新迁移甚至没有运行;好像你有另外两个都试图创建用户表('DeviseCreateUsers'和一个较老的迁移)。你应该改变'DeviseCreateUsers'来使用'add_column's而不是试图创建表。 – fwalch

回答

10

Rails的跟踪的迁移在你的数据库的“schema_migrations”表。除非有一个条目“20120511224920”,这是Devise迁移,它将尝试再次运行它,它似乎已经存在。

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

+1

我没有意识到这一点。我运行了一个rake db:reset,所以现在唯一的迁移是新的。如果我想知道schema_migrations表,我至少可以检查一下。 – Catfish

+0

尽管我无法确定这是什么问题,但我猜测schema_migrations表中缺少一条记录。 – Catfish

6

错误是说,它试图重新运行原有DeviseCreateUsers迁移,不能因为用户表已经存在。

要解决此问题,可以运行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

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

+0

如果我运行向下迁移虽然,这将删除我的表和所有的数据在那里是正确的?根据你发布的指南,我应该能够添加一个新的迁移并运行rake数据库:migrate应该能够判断是否有任何迁移已经运行,而不是这次运行那些迁移。 – Catfish

+1

你说得对。我假定你在开发模式下运行,重新创建用户表是可以接受的。 Rails应该能够告诉你已经运行的是什么迁移。我刚刚读了其他答案的评论。你有两个运行'create_table:users'的迁移吗? – GorrillaMcD

1

我想你跑rails generate devise user某时产生DeviseCreateUsers。如果您已创建用户模型和用户表,则可以从db/migrate中删除生成的迁移文件。

+0

但是,如果我删除生成的迁移,当我移到生产并在新数据库上运行迁移时,我将缺少一些迁移。 – Catfish

+0

我认为你已经有了用于创建用户表的另一个迁移。 – Yanhao

+0

我确实有用于创建用户表的另一个迁移。 – Catfish

4

你可以尝试做一个新的数据库,然后再进行迁移:

rake db:drop:all 
rake db:create:all 
rake db:migrate 
+0

我做了一个rake db:reset,然后运行rake:db:migrate,但是这仍然不能解释为什么我不能创建一个新的迁移并运行它。 Rails通常可以很好地处理这个问题。 – Catfish

2

所以从我从这个云集:

  • 您已经有了一个User模型
  • 您有一个版本的这个生产
  • 你跑了默认的轨道产生色器件:安装
  • 然后您运行rails generate devise用户

我希望:

  • 您使用源代码控制
  • 您在很多

注意检查代码:如果不是,你要学习,为什么你需要这样做。

还原你的代码,您生成设计

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

重新运行设计一代

  • READD宝石 '设计' 到您的Gemfile
  • 轨产生色器件:安装
  • 轨生成设计模型

确保模型做不存在!如果你没有解决你目前遇到的问题。

从一个模型迁移当前用户对其他

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

编辑:你也许可以找到一种方法来定制Devise来代替使用你的算法。这可能会更好,但更多的工作和相当脆弱。

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

+0

幸运的是,我现在还没有生产,所以我最终只是删除了我的数据库数据,但我只是想知道什么会导致create_table脚本尝试再次运行,而不是正确跳过它并运行新的使用add_columns迁移 – Catfish

+0

哦,那么你不需要迁移用户,但我仍然可以从帐户数据中分离认证数据。至于正确性,Rails假设你想在迁移中做所有事情。要将用户用作身份验证模型,您需要在运行“rails generate devise model”命令之前从数据库中删除旧的。 –

0

只是尝试

在第一个文件

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

这将覆盖任何其他表

+0

但这会覆盖我的表是否正确?正如你可以从所有其他评论中看到的那样,我试图将列添加到数据库中,而不必删除数据。 Rails能够处理这个问题。 – Catfish

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. 

像耙分贝:迁移:缩小版本=版本号的#Version号是你要迁移的版本。

+0

为什么没有创建一个类似这样的'rails生成迁移AddDetailsToUsers ....'的迁移时创建的向上和向下方法.... – Catfish

+0

嗨。向上和向下方法将在rails 2.2.2中生成。 – vijikumar

+1

Rails 3.1通过提供新的更改方法使迁移变得更加智能。此方法对于编写建设性迁移(添加列或表)是首选。迁移知道如何迁移数据库并在迁移回滚时将其反转,而无需编写单独的停用方法。 所以看起来你不用担心def self.down,因为Rails现在足够聪明,知道如何回滚它。 – vijikumar

1

检查可能为迁移版本提供意外值的一些环境变量。我发现堆栈溢出an old question(并原谅我,如果它是过时的)其中db:migrate破坏表,而不是应用现有的新迁移。

他们最终发现,一个环境变量是造成db:migrate用的“0”的版本参数是功能上等同于rake db:migrate:down

运行是有可能,你的情况可以通过版本而造成意外地改变包括或匹配以前的移民DeviseCreateUsers

+0

我不这么认为,因为所有的迁移对它们都有不同的时间戳 – Catfish

0

根据你说你用这个命令来创建一个新的迁移

$轨产生迁移AddDetailsToUsers HOME_PHONE:小数cell_phone:小数work_phone:小数生日:日期home_address:文本work_address:文本位置:串公司:字符串

林不知道它只是一个错字,但它应该是“AddDetailsToUser”而不是“用户”。只需再次检查,我们将能够为您提供帮助。这是为设计生成的模型。当你提到用户,在分贝它寻找用户。

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

如果你想使用表名,然后使用这个

轨摹迁移add_details_to_users HOME_PHONE:小数......等

0

如果你需要手动做一些肮脏的迁移:

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

A.new.migrate(:up) 
相关问题