postgresql 将Postgres枚举类型与Rails一起使用时,在迁移中将CREATE TYPE xyz_setting指定为ENUM会破坏db/schema.rb文件

kxxlusnw  于 2023-01-17  发布在  PostgreSQL
关注(0)|答案(4)|浏览(94)

这是基于www.example.com上的一些dev.to文章,这里是https://dev.to/diegocasmo/using-postgres-enum-type-in-rails-30mo,这里是https://dev.to/amplifr/postgres-enums-with-rails-4ld0,这里是同一个人的文章https://medium.com/@diegocasmo/using-postgres-enum-type-in-rails-799db99117ff
如果您遵循上面的建议,建议您通过直接在Postgres上使用CREATE TYPE xyz_setting AS ENUM为Postgres支持的模式创建Rails模式迁移,然后使用它创建新字段作为ENUM(postgres枚举)
不幸的是,这种方法有破坏db/schema.rb文件的缺点。
我认为问题在于Rails核心不支持原生Postgres类型。
我可以在Rails 5.17、www.example.com和6.0.3上重现这种行为5.2.2.4
如果我做了...

class AddXyzToUsers < ActiveRecord::Migration[5.2]
  def up
    execute <<-DDL
          CREATE TYPE xyz_setting AS ENUM (
            'apple', 'bananna', 'cherry'
          );
    DDL
    add_column :users, :xyz, :xyz_setting
  end

  def down
    remove_column  :users, :xyz
    execute "DROP type xyz_setting;"
  end
end

那么我的模式文件就混乱了,具体来说,schemausers表没有得到输出whatseover,取而代之的是以下消息

由于以下标准错误,无法转储表“users

列“xyz”的未知类型“xyz_setting”

to94eoyn

to94eoyn1#

PostgreSQL(Rails 7+)中的自定义枚举类型

Rails 7 added support for custom enum types in PostgreSQL.
现在,迁移可以编写如下:

# db/migrate/20131220144913_create_articles.rb
def up
  create_enum :article_status, ["draft", "published"]

  create_table :articles do |t|
    t.enum :status, enum_type: :article_status, default: "draft", null: false
  end
end

# There's no built in support for dropping enums, but you can do it manually.
# You should first drop any table that depends on them.
def down
  drop_table :articles

  execute <<-SQL
    DROP TYPE article_status;
  SQL
end

另外值得一提的是,当您使用create_enum时,枚举定义和枚举列将在schema.rb中呈现。

qyyhg6bp

qyyhg6bp2#

Rails不支持开箱即用的自定义PG类型。
正如Diego Castillo所述,您可以使用SQL模式来处理这些类型。
但是,如果您想继续使用ruby模式,可以使用activerecord-postgres_enum,这是一个gem,它支持PostgreSQL枚举数据类型。

tkclm6bt

tkclm6bt3#

在Rails 7中,如果您正在使用PostgreSQL,现在可以执行以下操作:

rails generate model Post title:string body:text post_type:enum

您的迁移可能类似于:

class CreatePosts < ActiveRecord::Migration[7.0]
  def change
    create_enum :post_option, ["draft", "private", "published"]
    
    create_table :posts do |t|
      t.string :title
      t.text :body

      t.enum :post_type, enum_type: "post_option", default: "draft", null: false

      t.timestamps
    end
    add_index :posts, :post_type
  end
end

您的模式如下所示:

ActiveRecord::Schema[7.0].define(version: 2022_06_04_221707) do
  ...
  create_enum "post_option", ["draft", "private", "published"]
  ...
  create_table "posts", force: :cascade do |t|
    t.string "title", default: ""
    t.text "body", default: ""
    t.enum "post_type", default: "draft", null: false, enum_type: "post_option"
    t.string "image", default: ""
    t.index ["post_type"], name: "index_posts_on_post_type"
  end
end

然后,在您的模型上,您需要添加:

enum :post_type, draft: "draft", private: "private", published: "published"
pokxtpni

pokxtpni4#

    • 对于Rails 7,Postgres枚举支持现已内置**

我非常喜欢@crysicia的回答,但更准确地说,对于下一位开发人员,对于Rails 6,您可以选择以下两种方式之一:
1.使用activerecord-postgres_enum
1.将您的Rails应用程序切换到SQL模式(假设您在db/schema.rb使用本地Rails模式),这将生成db/structure.sql,当然将使用本地SQL编写您的模式。
第二种方法当然不受Rails-DB分离纯粹主义者的欢迎,但无论如何,整个实现都是如此,因为我不知道还有其他支持枚举的DB(可能有)。
因此,基本上,如果您希望保留db/schema.rb,我建议使用activerecord-postgres_enum gem

相关问题