Adding new changeset arguments in `before_action`

Hi, I'm having a bit of trouble understanding the order in which changes get executed within an update action and how to set arguments. Suppose I have something like:
update :foo do
require_atomic? false

accept []

argument :arg1, :string, allow_nil?: false

change before_action(fn changeset, _context ->
record = changeset.data

nested_resource = NestedResource.create!(%{parent_id: record.id})

Ash.Changeset.set_argument(changeset, :nested_resource_id, nested_resource.id)
end)

change fn changeset, _context ->
dbg(changeset.arguments)

changeset
end
end
update :foo do
require_atomic? false

accept []

argument :arg1, :string, allow_nil?: false

change before_action(fn changeset, _context ->
record = changeset.data

nested_resource = NestedResource.create!(%{parent_id: record.id})

Ash.Changeset.set_argument(changeset, :nested_resource_id, nested_resource.id)
end)

change fn changeset, _context ->
dbg(changeset.arguments)

changeset
end
end
Running :foo on a resource prints the following in the IEx:
arguments #=> %{
nil: "0198908a-c4ca-7c4f-831e-b67ea589f4c8",
arg1: "description"
}
arguments #=> %{
nil: "0198908a-c4ca-7c4f-831e-b67ea589f4c8",
arg1: "description"
}
where the value associated with nil is the nested_resource.id. I have two questions: 1. At what point do changes that are not before_action, etc get run? 2. Is this a bug that an argument gets a key of nil instead of :nested_resource_id?
8 Replies
ZachDaniel
ZachDaniel•2mo ago
https://hexdocs.pm/ash/actions.html#complete-lifecycle-flow THe changes run first and then any before actions that were added run after that
Igor Barakaiev
Igor BarakaievOP•2mo ago
How is it that in the example above the arguments get populated with :nested_resource_id's value under nil key? 🤔
ZachDaniel
ZachDaniel•2mo ago
🤔 I have no idea actually Does that not happen if you remove the before_action change above it? THat seems unrelated to me TBH
Igor Barakaiev
Igor BarakaievOP•2mo ago
if instead of just doing set_argument I do something hacky like Map.put(changeset, :arguments, Map.put(changeset.arguments, :nested_resource_id, nested_resource.id)), then the debug actually prints:
arguments #=> %{
nested_resource_id: "0198908a-c4ca-7c4f-831e-b67ea589f4c8",
arg1: "description"
}
arguments #=> %{
nested_resource_id: "0198908a-c4ca-7c4f-831e-b67ea589f4c8",
arg1: "description"
}
ZachDaniel
ZachDaniel•2mo ago
oh wow its because there is no such argument with that name it must be a bug w/ how we handle that please open an issue you can't set_argument for args taht don't exit
Igor Barakaiev
Igor BarakaievOP•2mo ago
ah damn, I was kind of depending on running set_argument to add new arguments dynamically 🫣 (in my hacky way)
ZachDaniel
ZachDaniel•2mo ago
You can use set_context and read from context You can also have private arguments
Igor Barakaiev
Igor BarakaievOP•2mo ago
ah yes, that's the right approach. I'll open an issue about the nil thing

Did you find this page helpful?