簡體   English   中英

Rails 5 Postgres:是否有包含的數據庫約束?

[英]Rails 5 Postgres: Is there a DB constraint for inclusion?

我試圖確保(盡可能)我的每個模型驗證都有等效的數據庫約束。 我的很多模型都有一個status列,我正在使用inclusion:驗證來確保狀態值在我的白名單數組中。

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

是否有可以添加到create_table遷移的數據庫的等效約束?

(在 Postgres 中使用 Rails 5.2.4.1)

Postgres 有一個原生的枚舉類型,它實際上在很多方面都比約束更好。

枚舉 (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 功能來說,確實如此。

如果我理解正確的話,您要查找的數據庫約束要么是檢查約束,要么是外鍵約束。

對於檢查約束,您可以像這樣運行 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)
);

檢查約束更能抵抗更改(您必須更改數據庫架構才能添加或刪除有效狀態); 外鍵更容易更改(只需添加或刪除一行),但更容易“篡改”。 無論您使用哪一種,應該很少有人擁有足夠的權限來更改這些限制。 真的很少。

但是,恕我直言,Rails 忽略了您可能需要考慮的問題更多的數據庫約束。

這個助手在對象被保存之前驗證屬性的值是唯一的。 它不會在數據庫中創建唯一性約束。 . . (來自Uniqueness helper 文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM