Skip to content

Upsert all restore soft-deleted record accidentally #570

@mahdiar-naufal-shyftplan

Description

When upsert records with upsert_all method on AR 7.0 above, Paranoia restore any matching deleted record.
The sql from AR 6 returned something like this if we do an upsert from the added test:

INSERT INTO \"employers\" (\"id\",\"name\") VALUES (1, 'new_e1'), (2, 'new_e2') ON CONFLICT (\"id\") DO UPDATE SET \"name\"=excluded.\"name\"

With AR 7, InsertAll includes scope keys automatically, generates sql into something like this:

INSERT INTO \"employers\" (\"id\",\"name\",\"deleted_at\") VALUES (1, 'new_e1', NULL), (2, 'new_e2', NULL) ON CONFLICT (\"id\") DO UPDATE SET \"name\"=excluded.\"name\",\"deleted_at\"=excluded.\"deleted_at\" RETURNING \"id\"

How to reproduce:
use this test, it will fail on AR 7.0+

def test_upsert_all_on_soft_deleted_record
    e1 = Employer.create(name: "e1")
    e2 = Employer.create(name: "e2", deleted_at: Time.current)
    assert_nil e1.deleted_at
    assert e2.deleted_at != nil

    Employer.upsert_all([
      { id: e1.id, name: "new_e1" },
      { id: e2.id, name: "new_e2" }
    ])

    assert e1.reload.name == "new_e1"
    assert e2.reload.name == "new_e2"

    assert_nil e1.reload.deleted_at
    assert e2.reload.deleted_at != nil
  end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions