Rails 5 Postgres: есть ли ограничение БД для включения? - PullRequest
1 голос
/ 16 января 2020

Я пытаюсь обеспечить (насколько это возможно), чтобы у меня были эквивалентные ограничения базы данных для каждой из моих проверок модели. У многих моих моделей есть столбец status, и я использую проверку inclusion:, чтобы убедиться, что значение состояния находится в моем белом списке.

validates :status, inclusion: { in: %w[pending active inactive] }

Существует ли эквивалентное ограничение для БД, которое Я могу добавить к миграции create_table?

(Использование Rails 5.2.4.1 с Postgres)

Ответы [ 2 ]

3 голосов
/ 16 января 2020

Postgres имеет собственный тип перечисления , который во многих отношениях лучше, чем ограничение.

Перечислимые (перечисляемые) типы - это типы данных, которые включают stati c, упорядоченный набор значений. Они эквивалентны типам enum, поддерживаемым во многих языках программирования. Примером типа enum могут быть дни недели или набор значений состояния для фрагмента данных.

Это относится к популярной критике целочисленных столбцов ActiveRecord :: Enum, которые просто глядя из базы данных, вы не можете сказать, что на самом деле означают статусы. Это также не то же самое, что просто использование строкового столбца, поскольку значения сопоставляются с таблицей поиска и занимают только 4 байта на диске.

class AddStatusToProjects < ActiveRecord::Migration[5.2]
  def up
    execute <<-SQL
      CREATE TYPE project_status AS ENUM ('pending', 'active', 'inactive');
    SQL
    add_column :project, :status, :project_status
  end

  def down
    remove_column :projects, :status
    execute <<-SQL
      DROP TYPE project_status;
    SQL
  end
end

Затем настройте явное отображение для Enum в вашей модели:

class Project < ApplicationRecord
  enum status: {
    'pending' => :pending,
    'active' => :active,
    'inactive' => :inactive
  }
  # ...
end

Postgres обеспечит правильность значений для типа:

irb(main):022:0> Project.create!(status: 'foo')
   (0.3ms)  BEGIN
  Project Create (3.6ms)  INSERT INTO "projects" ("created_at", "updated_at", "status") VALUES ($1, $2, $3) RETURNING "id"  [["created_at", "2020-01-16 14:15:47.579769"], ["updated_at", "2020-01-16 14:15:47.579769"], ["status", "foo"]]
   (0.4ms)  ROLLBACK
Traceback (most recent call last):
        1: from (irb):22
ActiveRecord::StatementInvalid (PG::InvalidTextRepresentation: ERROR:  invalid input value for enum project_status: "foo")

Самое большое преимущество в том, что вам нужно использовать схему SQL вместо ruby Схема, поскольку она не может сбросить таблицу. Но это верно для многих Postgres функций.

2 голосов
/ 16 января 2020

Если я вас правильно понимаю, то ограничение базы данных, которое вы ищете, это либо ограничение проверки, либо ограничение внешнего ключа.

Для ограничения проверки вы должны выполнить SQL что-то вроде этого.

alter table your_table
  add constraint constraint_name
  check (status in ('pending', 'active', 'inactive');

Для ограничения внешнего ключа сначала нужно создать таблицу допустимых состояний.

create table statuses (
  status varchar(15) primary key
);
insert into statuses values 
('pending'), ('active'), ('inactive');

И в справочной таблице. , .

create table your_table (
  other_columns char(1) primary key,  
  status varchar(15) not null
    references statuses (status)
);

Ограничение проверки более устойчиво к изменениям (необходимо изменить схему базы данных, чтобы добавить или удалить допустимые состояния); внешний ключ легче изменить (просто добавить или удалить строку), но он более открыт для «подделки». Независимо от того, какой из них вы используете, относительно немногие люди должны иметь достаточные привилегии для изменения этих ограничений. Очень мало.

Но, IMHO, Rails пропускает гораздо более проблемное ограничение c базы данных, о котором вам, вероятно, нужно подумать.

Этот помощник проверяет, что значение атрибута уникально прямо перед сохранением объекта. Это не создает ограничение уникальности в базе данных. , , (Из Документация помощника по уникальности )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...