Scenario

There is an existing Invoice model in the application. A new column is being introduced to add a Reference.

We must backfill all existing Invoices with a Reference.

Upsert all

Attempt to backfill using upsert_all. We want to update only the reference column on all Invoices, but leave all other columns untouched.

invoices = Invoice.where(reference: nil)
invoice_ids = invoices.pluck(:id)

upsert_attrs = invoice_ids.map do |invoice_id|
  {id: invoice_id, reference: generate_reference}
end

invoices.upsert_all(upsert_attrs, unique_by: :id)

This code produces an error of No unique index found for id

Expected

Before backfilling

id amount paid notes reference
1 100.00 true    
2 200.00 true Returned  
3 500.00 false Due end of month  

After backfilling

id amount paid notes reference
1 100.00 true   X122791
2 200.00 true Returned AC12911
3 500.00 false Due end of month ABI1000

Thoughts

It is unclear if this code block should work or if this is not the intended use case for upsert_all.

It could be an older issue on Rails 6.0.