I recently updated from an early Ash 3.x to the most recent, and find at runtime a lot of warnings like:
Changeset has already been validated for action :create.
For safety, we prevent any changes after that point because they will bypass validations or other action logic.. To proceed anyway, you can use `force_change_attribute/3`. However, you should prefer a pattern like the below, which makes any custom changes *before* calling the action.
Resource
|> Ash.Changeset.new()
|> Ash.Changeset.change_attribute(...)
|> Ash.Changeset.for_create(...)
So far in my application I have a lot of actions that use Ash.Changeset.change_attribute/3
within change before_action(fn ....)
blocks. This is usually to support computed defaults that depend on other attributes/arguments so that the call sites for the actions are nice and clean.
The simplest thing is to change all these occurrences to Ash.Changeset.force_change_attribute/3
but the warning advises against it.
I could write wrapper functions for all these actions that compute the defaults before calling the action, as advised by the warning, but then the actions themselves become far less convenient to call directly, and the functions will be located elsewhere in the module, not right next to the action they are related to.
Maybe wrapper actions would be better, so have a create :raw_create
that defaults nothing, and create :create
would accept no attributes, only arguments, compute the defaults and call the raw_create
action, but that feels verbose and undesirable.
Validations could be removed from the attributes and applied explicitly within each action, but that would lose a lot of the attribute metadata and be more repetitive and error prone.
I don’t see a change before_validation
hook but if it existed that would be a simple fix.
It feels like I’ve been using Ash wrong but it’s unclear what the best approach is, perhaps I’m missing something obvious that I didn’t notice in the docs.