[英]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.