另一种可能有人遇到这种情况的情况是在将您的自定义类型(枚举)插入 PostgreSQL 时。如果这样做并且仍然想在不使用 SQL 转储器的情况下转储您的 schema.rb,您可以将自定义数据库类型添加到适配器的有效类型列表中。
2021-08-13 更新:评论者指出,可能有比我下面的建议更简单的方法来做到这一点。
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:my_custom_type] = { name: "my_custom_type_name" }
原始建议
例如,假设您有一个Customer
带有status
andpriority
并且您想使用 postgres 的本机枚举类型。您需要在迁移中手动进行一些设置,并且需要一个初始化程序来帮助 Rails 生成您的模式。
迁移
class CreateCustomers < ActiveRecord::Migration[5.2]
def up
execute <<-SQL
CREATE TYPE type_status AS ENUM ('active', 'inactive');
CREATE TYPE type_priority AS ENUM ('high', 'medium','low');
SQL
create_table :customers do |t|
t.string :name
t.column :status, :type_status
t.column :priority, :type_priority
end
end
def down
drop_table :customer_addresses
execute <<-SQL
DROP TYPE status;
DROP TYPE priority;
SQL
end
end
初始化器。
# config/initializers/postres_custom_enum_types.rb
# Following only needed if the adapater isn't loaded for some reason - e.g.
# if you have no models in your app.
require "active_record/connection_adapters/postgresql_adapter"
module ActiveRecord
module ConnectionAdapters
if const_defined?(:PostgreSQLAdapter)
class PostgreSQLAdapter
NATIVE_DATABASE_TYPES.merge!(
enum: { name: 'enum' },
# there is a chance the above causes conflicts in some cases, you can
# always be more explicit and actually use your type or names (I am not looking up which)
# type_priority: { name: 'enum' }
)
end
end
end
end
验证此解决方案
这就是您将在数据库中看到的内容。
enum_in_db_development=# INSERT INTO customers VALUES (1, 'Mario','active','high');
INSERT 0 1
enum_in_db_development=# INSERT INTO customers VALUES (1, 'Mario','active','notthere');
ERROR: invalid input value for enum type_priority: "nothere"
LINE 1: INSERT INTO customers VALUES (1, 'Mario','active','notthere')
^
enum_in_db_development=# SELECT enum_range(NULL::type_priority);
enum_range
-------------------
{high,medium,low}
(1 row)
关于我的解决方案的注意事项:
- 我正在检查是否存在,
PostgreSQLAdpater
因为我使用的静态分析 gem 部分加载了一些 AR 依赖项 - 特别是 gem annotate
。
- NATIVE_DATABASE_TYPES 的原始定义的来源是 rails 6。
我遇到此问题的背景:当我在 rails 5.0.x 中发生这种情况时,迁移运行良好,但是当我尝试运行db:test:prepare
或db:reset
. 我花了很长时间才找到模式转储问题。