Как использовать перечисление в базе данных Postgres в Rails 3?
PostgreSQL имеет концепцию перечисляемых типов, встроенных в базу данных.
Как бы вы реализовали таблицу со столбцом, который использует перечисляемый тип в Rails 3? Вам нужно каким-то образом определить перечисление в PostgreSQL? Как можно создать миграцию базы данных, которая делает это?
Работает в Rails 3.07, Ruby 1.92p180, PostgreSQL 8.3.
Ответы
Ответ 1
Rails не поддерживает тип данных ENUM
из коробки. Это связано с тем, что не все базы данных поддерживают этот тип данных. Я обнаружил, что общий способ использования значений ENUM
- это вручную создать столбец перечисления в вашей базе данных (PostgreSQL в вашем случае) и обработать его как столбец string
в вашем приложении Rails. Затем используйте validates_inclusion_of для принудительного использования разрешенных значений.
validates_inclusion_of :gender, :in => [ "male", "female" ]
И используйте родной SQL в вашей миграции, чтобы добавить поле перечисления:
class AddEnumType < ActiveRecord::Migration
def up
execute ".." # your native PostgreSQL queries to add the ENUM field
end
end
edit (июнь 2014 года)
Rails 4.1 теперь поддерживает перечисления. Теперь параметр validates_inclusion_of
можно изменить на:
enum gender: [ :male, :female ]
(Тем не менее, эта поддержка по-прежнему не поддерживается базовой базой данных, поэтому миграция на родном SQL по-прежнему необходима.)
Ответ 2
Вы также можете настроить схему на использование raw SQL вместо файла .rb. Если вы используете более сложные функции базы данных (перечисления, полнотекстовый поиск, триггеры, функции и т.д.), А не просто использовать ее в качестве общего хранилища данных, это упростит вашу жизнь.
Просто установите эту строку в файле config/application.rb
# Use SQL for the schema due to many database specific settings
config.active_record.schema_format = :sql
Он выведет файл structure.sql, который решит эту проблему для вас.
Ответ 3
В дополнение к приведенным выше ответам для Rails 4 (и, возможно, 3.2) вы можете сделать это, чтобы избежать предупреждений типа "Недопустимый идентификатор OID":
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID.alias_type 'my_enum_type', 'text'
При запросе вы также захотите преобразовать строку в свой тип, например
scope :my_enum_value_is, ->(value){
where('my_enum_value = ?::my_enum_type', value)
}
Вы также захотите исправить парсер столбца:
class ActiveRecord::ConnectionAdapters::Column
private
def simplified_type_with_my_enum_type(field_type)
if field_type == 'my_enum_type'
field_type.to_sym
else
simplified_type_without_my_enum_type(field_type)
end
end
alias_method_chain :simplified_type, :my_enum_type
end