繁体   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