如何定义在 Rails 5.2 上的 Ruby ActiveRecord 迁移中创建 table 时使用的序列?

How to define the sequence to use when creating a table in ActiveRecord migration in Ruby on Rails 5.2?

我需要为我的 table 的 ID 字段分配一个特定的 Postgres 序列。在模型中,我尝试定义以下对 Posgres 没有影响的设置:

class MyObject < ActiveRecord::Base

self.sequence_name = "global_seq"

通常,ActiveRecord 迁移中的 table 定义以

开头
create_table "objects", id: :serial, force: :cascade do |t|

生成列默认值的 Postgres 定义为

default nextval('objects_id_seq'::regclass)

如何在迁移中指定 nextval() 函数应依赖于另一个序列?

恐怕 Rails' 迁移没有内置命令来显式设置列的顺序。它非常特定于数据库。

但是可以使用普通 SQL:

class ChangeSequenceOfObjectId < ActiveRecord::Migration[5.0]
  def self.up
    execute <<-SQL
      CREATE SEQUENCE global_seq;
      ALTER TABLE objects ALTER COLUMN id SET DEFAULT nextval('global_seq');
      ALTER SEQUENCE objects_id_seq OWNED BY NONE;
      ALTER SEQUENCE global_seq OWNED BY objects.id;
    SQL
  end

  def self.down
    execute <<-SQL
      ALTER TABLE objects ALTER COLUMN id SET DEFAULT nextval('objects_id_seq');
      ALTER SEQUENCE objects_id_seq OWNED BY objects.id;
      ALTER SEQUENCE global_seq OWNED BY NONE;
      DROP SEQUENCE global_seq;
    SQL
  end

如果 global_seq 序列是在其他迁移中创建的,则只需删除有关其创建/删除的相应行。

如果您想将 global_sql 序列保留为 'free-standing',也可以删除 ALTER SEQUENCE global_seq OWNED BY 命令(即使 objects table 保留在数据库中下降)。

您可以在迁移中更改默认值:

change_column :my_objects, :id, :integer, default: -> { "nextval('global_seq')" }

您可能希望使用 :bigint 而不是 :integer,具体取决于序列和表格的设置方式。您必须对 :default 选项使用 lambda 才能将原始 nextval('global_seq') 表达式导入数据库。

您可能还想删除旧序列,据我所知,您必须为此使用 connection.execute('drop sequence ...')

如果您跳过 create_table 中的默认 :id 步骤,那么您可以在手动创建 :id 列时完成所有操作:

create_table :my_objects, id: false do |t|
  t.bigint :id, null: false, default: -> { "nextval('global_seq')" }
  t.primary_key :id
  ...
end

同样,t.bigintt.integer 之间的选择取决于您希望 PK 有多大。

我使用 sequence_name 选项 (Rails 5.1):

create_table "opjects", sequence_name: 'global_seq' do |t|

我没有检查,但我想,在 Rails 5.2 中它应该也可以。