Rails 在插入和更新时使用 upsert_all

Nic*_*llo 7 postgresql activerecord ruby-on-rails

我正在尝试使用该upsert_all方法在 Postgres 数据库中同时更新和插入所有记录(来自 ActiveRecord 模型)。但是,我遇到了一个问题。
我首先获取现有记录并更新它们,这是有意义的,因为使用该方法更新它需要记录 ID(这是我的主键)upsert_all
不过,对于新记录,我没有 ID,但必须根据upsert_all需要设置一个 ID,以便所有记录具有相同的键,因此我必须设置 ID,而且我认为设置它可能会nil起作用。执行此操作时,我收到以下错误: PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraint

那么我应该如何upsert_all在 Rails 中使用该方法?
有没有办法指定如果 ID 为 nil,则该值将被 postgres 绕过并自动递增?

Jon*_*Jon 6

Rails 文档中的示例应该告诉您需要了解的所有内容:

# Inserts multiple records, performing an upsert when records have duplicate ISBNs.
# Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.

Book.upsert_all([
  { title: "Rework", author: "David", isbn: "1" },
  { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
], unique_by: :isbn)

Book.find_by(isbn: "1").title # => "Eloquent Ruby"
Run Code Online (Sandbox Code Playgroud)

所以...不,您不需要知道记录的 ID。您如何知道尚未创建的记录的 ID?但是,您应该指导该upsert_all方法如何通过传递来识别要更新的记录unique_by

另一个例子可能是更新一群用户。是的,他们在数据库中都会有一个 ID,但他们也应该有一个唯一的电子邮件或用户名或其他东西:

User.upsert_all([
  { email: "bob@acme.com", role: "manager" },
  { email: "new-user@example.com", role: "customer" }
], unique_by: :email)
Run Code Online (Sandbox Code Playgroud)

在此示例中,bob@acme.com已经存在,但new-user@example.com不存在。鲍勃的角色已更新,新用户的帐户已创建。