ruby-on-rails 如何在Rails Active Record中实现“写入两列”(正如Strong migrations所建议的)?

jtw3ybtb  于 2023-05-23  发布在  Ruby
关注(0)|答案(2)|浏览(227)

我试图改变PostgreSQL(Rails 6)中列的类型。

迁移:

# frozen_string_literal: true

class ChangeUsersEmailToCitext < ActiveRecord::Migration[6.0]
  def up
    enable_extension('citext')

    change_column :users, :email, :citext
  end

  def down
    change_column :users, :email, :string
  end
end

但强迁移抛出错误,并说如下:

=== Dangerous operation detected #strong_migrations ===

Changing the type of an existing column blocks reads and writes
while the entire table is rewritten. A safer approach is to:

1. Create a new column
2. Write to both columns
3. Backfill data from the old column to the new column
4. Move reads from the old column to the new column
5. Stop writing to the old column
6. Drop the old column

我明白db锁定的意义和危险。。但我的问题很傻,我还没有找到答案。我怎么能做到第二、第四和第五点?如何强制ActiveRecord模型同时写入两个列,并在回填后切换到正确的列?

3lxsmp7m

3lxsmp7m1#

假设旧列为length,新列为length_advanced
2 -写入两列

def length=(value)
  super(value)
  self[:length_advanced] = value
end

4 -将读取从旧列移动到新列

def length
  if super.present?
    super
  else
    self[:length_advanced]
  end
end

5 -停止向旧栏中写入内容

def length=(value)
  # no write to old column
  self[:length_advanced] = value
end

更多关于https://api.rubyonrails.org/classes/ActiveRecord/Base.html

qqrboqgw

qqrboqgw2#

在你的情况下,这应该起作用:

class ChangeUsersEmailToCitext < ActiveRecord::Migration[6.1]
  def up
   enable_extension('citext')
   add_column :users, :new_email, :citext

  Users.reset_column_information
  Users.find_each do |record|
   record.update(
     new_email: record.email.to_citext, // make conversion here
   )
  end

  safety_assured { remove_column :users, :email }

  safety_assured { rename_column :users, :new_email, :email }
 end

 def down
   raise ActiveRecord::IrreversibleMigration, "Reverting this migration is not supported"
 end  
end

相关问题