Can I instruct Ash to force update a CiString value regardless of comparison result?

I'm using Ash.CiString on a resource field (backed by postgres citext) for all the uniqueness constraint validation goodness, but recently discovered that Ash is skipping updates to the field value when only the case has changed. I know, I know: why am I using a CiString if I don't want case-insensitive comparison? Because I don't want to clobber other records with the same case-insensitive name. But I do want to give the user control to update the casing of the value on an individual record. I have a NameCollissionPrevention validation that ignores the current record in question when deciding if the record update is valid, so I don't think this is programmer error, it feels like Ash is ignoring the field in the update b/c it compares as equal. Maybe CiString isn't the right tool for the job in this scenario. I'm curious if Ash provides a way to say "you can update this value to anything (and any case) you want". Thanks in advance for any ideas you can provide.
Solution:
I ended up modifying it a bit b/c the :name arg isn't required: ``` change(fn changeset, _ctx -> case changeset.arguments[:name] do...
Jump to solution
4 Replies
localshred
localshredOP•7d ago
From what I can tell, the field :name is pulled from the attributes if the case-insensitive comparison returns a match. Is there a way to force that in? Maybe put a pre-action hook in place and put the name in a private context var, and then set it on the changeset? I tried adding a before_action but it appears to be running after (or inside?) my change action, even though the code is registered before it. Ok, if I add the :name field as an argument instead of just listing it as a field in accept it now comes through on the changeset and I can use force_change_attribute/3, but that's still not passing the value through to postgres to update
ZachDaniel
ZachDaniel•7d ago
Yeah...I legitimately hadn't considered this as a thing 😅 What you want to do makes perfect sense Try change atomic_update(:field, expr(^arg(:name)), cast_atomic?: false) We should add an option to change attribute not to compare with the old one but it's a bit complex. This is a hack to workaround it temporarily If that works LMK and we can open an issue about it 🙂
localshred
localshredOP•7d ago
I'll be damned, that worked. Not in a million years would I have thought about doing that. Thanks for saving my bacon yet again.
Solution
localshred
localshred•7d ago
I ended up modifying it a bit b/c the :name arg isn't required:
change(fn changeset, _ctx ->
case changeset.arguments[:name] do
nil ->
changeset

name ->
changeset
|> Changeset.atomic_update(:name, expr(^arg(:name)))
end
end)
change(fn changeset, _ctx ->
case changeset.arguments[:name] do
nil ->
changeset

name ->
changeset
|> Changeset.atomic_update(:name, expr(^arg(:name)))
end
end)

Did you find this page helpful?