Ash Change Callback called many times - why?

I’d like to understand why a change callback is called 3 times after submit for a single update.

The resource is

code_interface do
  define(:update, action: :update)
end

update :update do
  primary?(true)
  require_atomic?(false)

  change(
    fn changeset, _context ->
      IO.inspect([changeset])
      changeset
  end
  )
end

When calling AshPhoenix.Form.submit(socket.assigns.form, params: params), the changeset is printed 3 times on console. Why?

The changeset is also printed after AshPhoenix.Form.for_update(resource, :update).

I want to notify (only once) a pubsub channel that there was an update to the resource. How could I achieve that?

Thanks.

I’m not sure why it’s happening three separate times on form submission TBH. It should happen twice :slight_smile:

The body of change functions is expected to happen multiple times. Having things happen once is the purpose of hooks. For example:

change fn changeset, _context -> 
  Ash.Changeset.after_transaction(changeset, fn changeset, {:ok, result} ->
      # do a side effect here 
    {:ok, result}
   {:error, error} ->
      {:error, error}
  end)
end

For your specific case, however, there is a pub sub extension built directly into Ash.

https://hexdocs.pm/ash/Ash.Notifier.PubSub.html

1 Like

Thanks, @zachdaniel.

This worked for me.

change after_transaction(fn
  changeset, {:ok, result}, _context ->
    # broadcast here
    {:ok, result}
  _changeset, result, _context ->
    result
end)

I would very highly encourage you to look at the pub sub built in notifier :slight_smile:

1 Like

I did it, but my application follows a very strict notification format, which differs from the Ash’s default format. Yesterday, I had to move on and couldn’t be stucked changing several parts of the system. For the next release, we will be using Ash’s notifier for the whole system.

Thanks again.

1 Like

You can also attach a custom notifier, which is just a module that defines notify/1, if you need to match your existing format :+1:

1 Like

I’ll give it a try. Thanks.