1

截至目前,我有一个包含列的用户表 id, name, email, status

statusfield 是一个整数类型,其值 1 和 2 分别代表一个活跃用户和非活跃用户。

我想将status字段更改为字符串类型并迁移数据 - 将 1 转换为“活动”,将 2 转换为“非活动”

我生成了2个迁移文件rails g migration

user.rb

class User < ApplicationRecord
  module Status
    ACTIVE = 'Active'.freeze
    INACTIVE = 'Inactive'.freeze

    ALL = [ACTIVE, INACTIVE].freeze
  end

  validates :status, presence: true
  validates :status, inclusion: Status::ALL
end

db/migrate/20190906115523_update_user_status_type.rb

def UpdateUserStatusType < ActiveRecord::Migration[5.2]
  def up
    change_column :users, :status, :string, default: User::Status::ACTIVE, 
  end

  def down
    User.where(status: User::Status::ACTIVE).update_all(status: 1)
    User.where(status: User::Status::INACTIVE).update_all(status: 2)
    change_column :users, :status, :integer, default: 1
  end
end

db/migrate/20190906115828_update_user_statuses.rb

def UpdateUserStatuses < ActiveRecord::Migration[5.2]
  def data
    User.where(status: 1).update_all(status: User::Status::ACTIVE)
    User.where(status: 2).update_all(status: User::Status::INACTIVE)  
  end
end

运行后rails db:migrate

Expected:迁移完成后,每个用户的状态都应转换为“活动”或“非活动”。

Actual Results:每个用户的状态都转换为"0"字符串类型。

4

1 回答 1

2

您假设在第一次迁移运行 ( change_column :users, :status, :string, default: User::Status::ACTIVE) 之后,您仍然可以从status列中获取旧值,但事实并非如此。当您将该列的类型更改为字符串时,所有整数值都是无效的,所以我怀疑您的数据库只是将所有无效值更改为“0”。

如果我被告知要对生产中大量使用的应用程序进行此更改,我将在几个单独的拉取请求/迁移中推出此更改。我会创建一个全新的单独列,遍历所有用户,根据旧列中的值设置新列的值,然后删除旧列。这是进行此更改的更安全的方法。

于 2019-09-08T22:11:57.510 回答