【问题标题】:Rails add index on year of created_atRails 在 created_at 年份添加索引
【发布时间】:2020-02-05 19:44:48
【问题描述】:

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

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

所以我试图在票表上添加一个关于 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 的机制。它在大部分时间都有效。但是,如果创建的两张票彼此非常接近,这将成为一个问题。

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

谢谢!

【问题讨论】:

  • 除了已有的答案之外,您还可以做的另一件事是让 Postgres 做自动增量部分,不要用 ruby​​ 做。

标签: ruby-on-rails postgresql indexing concurrency activesupport


【解决方案1】:

当您应该使用 PostgreSQL 语法时,您正在尝试使用 Ruby 语法。调用 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.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 2016-03-02
    • 2013-03-30
    • 1970-01-01
    • 2015-12-24
    • 2022-12-30
    • 1970-01-01
    相关资源
    最近更新 更多