Rollback record with Carbonite

tommasop
2023-04-12

tommasop:

I’m trying to achieve the title result. The problem is that trying to set some fields (like foreign keys and timestamps) back to their previous values will mark the changeset as invalid. I’m using force_change_attributes to try to overcome the problem but it is not woking. Is there a way to force the changeset to accept all attributes changes without validating them? Or is there a better way to achieve what I’m trying to achieve?

      customer_revert =
        Changeset.new(customer_update_two)
        |> Changeset.force_change_attributes(data_changes)
        |> MmsBiztalk.update!()
    ** (Ash.Error.Invalid) Input Invalid
     
     * Invalid value provided for updated_at: cannot be changed.
     
     ~U[2023-04-12 07:43:32.314706Z]
     
       (ash 2.6.29) lib/ash/changeset/changeset.ex:1037: anonymous fn/2 in Ash.Changeset.validate_attributes_accepted/2
       .....
     * Invalid value provided for data_in_id: cannot be changed.
     
     "8b4951f6-055c-4d9d-a498-8e2eeeb06e74"
     
       (ash 2.6.29) lib/ash/changeset/changeset.ex:1037: anonymous fn/2 in Ash.Changeset.validate_attributes_accepted/2
        ....
     code: |> MmsBiztalk.update!()

ZachDaniel:

Hmm…well, you don’t generally want to use Changeset.new

ZachDaniel:

The documentation for that function explains it

ZachDaniel:

And then I’d probably suggest:

Write an action that accepts all attributes and has arguments for all private/immutable attributes and uses something like change set_attribute(:updated_at, arg(:updated_at)) to force change them.

tommasop:

So here is the solution:

    update :force_update do
      argument :data_in_id, :uuid
      argument :updated_at, :utc_datetime_usec

      change set_attribute(:data_in_id, arg(:data_in_id))
      change set_attribute(:updated_at, arg(:updated_at))
    end
      customer_revert =
        customer_update_two
        |> Changeset.for_update(:force_update, data_changes)
        |> MmsBiztalk.update!()
        |> MmsBiztalk.load!([:data_in])

      assert customer_revert == customer