Rails 在 created_at 年添加索引

Rails add index on year of created_at

在我的 Rails 应用程序中,我有一张模型票。它的 created_at 字段 ActiveSupport::TimeWithZone。它还有一个整数类型的 number 字段。 number 字段不是主键。主键是一个 UUID。

任何一年,我都不能有2张相同号码的票。例如,在 2020 年,不允许有 2 张编号为 15 的工单。但是,如果它们是在不同年份创建的,则允许 2 张工单具有相同的编号。例如,2019 年创建的工单编号为 15,2020 年创建的工单编号为 15 --- 可以。

所以我试图在 table 的门票 created_at 的编号和年份上添加索引,并要求索引是唯一的:

class AddIndexToTickets < ActiveRecord::Migration[5.2]
  def change
    add_index :tickets, "number,(created_at.year)", unique: true, name: 'index_tickets_uniqueness'
  end
end

这会导致错误

PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "created_at"
LINE 1: ..." ON "tickets"  (number,(created_at...

这样做的原因是为了避免并发问题。在我的代码中,我有每次创建新票证时自动递增 number 的机制。它在大部分时间都有效。但是,如果创建的两张门票彼此非常接近,这将成为一个问题。

我该怎么办?我认为,自定义验证也可能会失败,具体取决于确切的时间。

谢谢!

你试图使用 Ruby 语法,而你应该使用 PostgreSQL 语法。调用 created_at.date 将在 Ruby ActiveSupport::TimeWithZone 对象上工作,但是您传递给 add_index 的参数将由 Postgres 计算,而不是 Ruby。所以它失败了,因为对于 Postgres,created_at.date 在这里是无效的语法。所以要修复它,你只需要切换到 PostgreSQL 语法。

我认为你可以通过这样的方式实现你想要的:

add_index :tickets, "number, EXTRACT(YEAR FROM created_at)", unique: true, name: 'index_tickets_uniqueness_on_year'.

未经测试,但应该可以。 More info on the EXTRACT function and other Postgres Date/Time stuff here.