Skip to content

Support updating records by id via :on_duplicate_key_update (#187)#220

Merged
Fivell merged 2 commits into
masterfrom
feature/upsert-by-id-on-duplicate-key-update
Jun 15, 2026
Merged

Support updating records by id via :on_duplicate_key_update (#187)#220
Fivell merged 2 commits into
masterfrom
feature/upsert-by-id-on-duplicate-key-update

Conversation

@Fivell

@Fivell Fivell commented Jun 15, 2026

Copy link
Copy Markdown
Member

Closes #187.

Context

Issue #187 asked for a way to update existing records based on an id column during import, instead of only inserting. This is already achievable through activerecord-import's upsert support (:on_duplicate_key_update), but the behaviour was untested and the README only mentioned it in passing ("For databases that support upserts you can use :on_duplicate_key_update instead.").

This PR proves it works and documents it properly.

What's here

  • Spec (spec/import_spec.rb): a new context under authors already exist that imports authors_with_ids.csv with

    active_admin_import validate: false,
                        on_duplicate_key_update: { conflict_target: [:id], columns: %i[name last_name birthday] }

    and asserts that a single import:

    • updates the colliding row (id 1 — stale birthday replaced, no duplicate created),
    • inserts the non-colliding row (id 2),
    • reports Successfully imported 2 authors.
  • README: replaced the one-line note with a concrete example and the two caveats that bite in practice:

    • conflict_target must name the unique column(s); MySQL infers and ignores it.
    • validate must be off for id-based upserts — activerecord-import runs uniqueness validations against the very rows the upsert is about to overwrite, so a model-level validates_uniqueness_of would reject the update (verified: with validate: true the existing-row update is dropped with "Last name has already been taken").
    • Active Record callbacks are not fired for bulk imports.

Verification

bundle exec rspec spec/import_spec.rb52 examples, 0 failures (3 new). Run locally on SQLite 3.53 / Rails 7.1 / Active Admin 3.2.

Fivell added 2 commits June 15, 2026 11:36
Issue #187 asked for updating existing records by id during import.
This is already possible through activerecord-import's upsert support,
but it was untested and only vaguely documented.

Add a spec proving a single import updates colliding rows (matched on
:id) and inserts non-colliding ones in one pass, and replace the
hand-wavy README note with a concrete example plus the validate:false
and callbacks caveats.
MySQL rejects the :conflict_target hash key (treats it as a column:
"Unknown column 'conflict_target'"). It infers the conflicting key on
its own, so it takes the bare column list, while PostgreSQL/SQLite need
the explicit conflict_target. Branch the option in the spec and document
both shapes in the README.
@Fivell Fivell force-pushed the feature/upsert-by-id-on-duplicate-key-update branch from 9b449e3 to ba06636 Compare June 15, 2026 09:37
@Fivell Fivell merged commit 3b01e3e into master Jun 15, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to update or create based on id column being present

1 participant