14

我将 Rails 3.1.1 与 PostgreSQL 9.1 和earthdistance 模块一起使用。为了能够正确计算不同位置之间的距离,我在表格中设置了一个earth类型的列branches

我现在遇到的问题是我使用此表的 Rails 应用程序不了解地球类型,因此我在我的db/schema.rb

# 由于遵循标准错误,无法转储表“分支”
# 列“位置”的未知类型“地球”

这是有问题的,因为现在我无法从 schema.rb 创建我的测试数据库。

如何将此类型添加到 AR 或使其忽略该列?

4

3 回答 3

18

另一种可能有人遇到这种情况的情况是在将您的自定义类型(枚举)插入 PostgreSQL 时。如果这样做并且仍然想在不使用 SQL 转储器的情况下转储您的 schema.rb,您可以将自定义数据库类型添加到适配器的有效类型列表中。


2021-08-13 更新:评论者指出,可能有比我下面的建议更简单的方法来做到这一点。

ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:my_custom_type] = { name: "my_custom_type_name" } 

原始建议

例如,假设您有一个Customer带有statusandpriority并且您想使用 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:preparedb:reset. 我花了很长时间才找到模式转储问题。

于 2017-08-01T06:24:24.457 回答
10

尝试这个:

改变你的 config/application.rb

config.active_record.schema_format = :sql

这会将输出格式更改为原生 PostgreSQL SQL 格式,schema.rb 将被禁用,并且将生成一个新文件 /db/config/structure.sql

于 2014-07-22T05:41:55.083 回答
4

对于访问此页面的任何人,有人已经在一个易于使用的 gem 中实现了这一点。

这就是您的迁移文件和模型文件的外观

# migration
class CreatePerson < ActiveRecord::Migration
  def change
    create_enum :mood, %w(happy great never_better)

    create_table :person do |t|
      t.enum :person_mood, enum_name: :mood
    end
  end
end

# model
class Person < ActiveRecord::Base
  enum mood: { happy: 'happy', great: 'great', never_better: 'never_better' }
end

https://github.com/bibendi/activerecord-postgres_enum

于 2020-05-28T18:48:28.367 回答