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