【问题标题】:Ruby on Rails 5.0 upgrade with migrating users table conflicts带有迁移用户表冲突的 Ruby on Rails 5.0 升级
【发布时间】:2016-11-06 16:18:10
【问题描述】:

从 4.2 升级到 Rails 5.0 后,我收到以下错误:

rails db:migrate
== 20160703164716 AddDeviseToUsers: migrating =================================
-- change_table(:users)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::DuplicateColumn: ERROR:  column "email" of relation "users" already exists
: ALTER TABLE "users" ADD "email" character varying DEFAULT '' NOT NULL
/Users/my_username/.rvm/gems/ruby-2.3.0/gems/activerecord-5.0.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:98:in `async_exec'
/Users/my_username/.rvm/gems/ruby-2.3.0/gems/activerecord-5.0.0/lib/active_record/connection_adapters/postgresql/database_statements.rb:98:in `block in execute'

阅读以下两篇 Stack Overflow 帖子后:

PGError: ERROR: column “email” of relation “users” already exists

Devise migration on existing model

我的问题是解决用户表发生的数据库冲突的最佳方法是什么?

最好编辑现有的迁移文件,例如 20160703164716 AddDeviseToUsers 迁移,还是建议进行新的迁移?

在我的开发环境和基于 Heroku 的生产环境中,进行新迁移的命令是什么,以及该迁移的最佳名称是什么,可以防止数据库冲突?

def self.up
  change_table(:users) do |t|
    t.recoverable
    t.trackable
    # rememberable uses remember_token, but this field is different
    t.rename :remember_token_expires_at, :remember_created_at
    # these fields are named differently in devise
    t.rename :crypted_password, :encrypted_password
  end
end

以上是第二篇文章中建议的代码。

您将如何使用此代码并从中进行新的迁移?

研究迁移后,我进行了以下迁移:

rails g migration change_data_type_for_users

根据我理解的上述错误建议在用户字段中修复的内容生成我编辑的新迁移。新的迁移代码:

class ChangeDataTypeForUsers < ActiveRecord::Migration[5.0]
  def change
    change_table(:users) do |t|
      t.string :email,              :null => false, :default => ""
  end
end

运行 rails db:migrate 后,我收到同样的错误。我究竟做错了什么?我现在应该回滚还是编辑新的迁移?

我后来发现了这篇 Stack Overflow 文章。 (Rails 4 Ruby 2.00 Devise migration on existing User Model fails) 这是正确的道路吗?删除数据库会删除所有数据库数据吗?

这里的另一个发现导致相信如果执行 rake db:reset 会破坏我数据库中的数据。这样做会重新创建数据库吗?目前尚不清楚,从下面的帖子看来,如果所有数据都被销毁,那将是非常具有破坏性的。我们只想修复一张表中的一个字段。

(Difference between rake db:migrate db:reset and db:schema:load)

我真的在尝试回答我自己的问题,所以也许这个模型对似乎由 ActiveAdmin 创建的用户模型产生了一些影响:

class AdminUser < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, 
         :recoverable, :rememberable, :trackable, :validatable
end

【问题讨论】:

  • 正如您从错误消息中看到的那样,“问题”是您正在添加电子邮件列,而它已经存在于您的用户表中。迁移没问题,似乎问题在于数据库版本(实际上已经包括电子邮件列)和迁移的不同步。尝试重置数据库(以防您没有任何敏感数据)。
  • 保罗,非常感谢。不幸的是,我确实有敏感数据,那就是担心或重置数据库。有没有办法返回此列并使用命令行将其删除?我找到了很多重置数据库的链接(stackoverflow.com/questions/10301794/…),但我担心数据库中其他敏感部分的数据。
  • 你可以删除列,是的。运行rails db,然后你会得到你的数据库控制台。阅读您的数据库引擎语法以更改表并删除列(除非它是 sqllite)
  • 如果数据库有敏感数据,请提前备份!

标签: ruby-on-rails database migration


【解决方案1】:

在您的情况下,请记住您正在尝试更改数据库中存在的列,您这样做的方式就像您正在创建一个新列一样。

t.string :email, :null => false, :default => ""

你可以把那行改成

t.change :email, :string, :null => false, :default => ""

在您的块内,知道“t”是您的用户表

【讨论】:

  • 这很有效,谢谢@Paul Bulanov 和@xploshioOn!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-09
  • 2019-12-24
  • 1970-01-01
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多