ash-project / ash

A declarative, extensible framework for building Elixir applications.
https://www.ash-hq.org
MIT License
1.63k stars 216 forks source link

Cannot write private attribute with force_change_attribute() #1304

Closed moxley closed 4 months ago

moxley commented 4 months ago

Describe the bug

For private attributes, I'm not able to create a valid changeset to change the attribute value.

The documentation says that the :public? option of the attribute DSL only affects public interfaces, such as AshGraphql and AshJsonApi: https://hexdocs.pm/ash/sensitive-data.html#public-private-attributes. But the Ash.Changeset module doesn't appear to be a public interface in the sense implied by the documentation.

Additionally, the documentation seems to apply the :public? option only affects reads, not writes, so force_change_attribute() shouldn't be required anyway.

To Reproduce

As demonstrated in this modification of ash's ChangesetTest: https://github.com/moxley/ash/commit/439d8267e2330a00b4144838abd465647cf79ba7

  1. Define an attribute that is not public.
  2. Start a new changeset on the attribute's resource module
  3. Use Ash.Changeset.force_change_attribute() to set the attribute's value
  4. Call Ash.Changeset.for_create().
  5. The changeset is not valid, and the validation error is %Ash.Error.Changes.InvalidAttribute{message: "Cannot be changed"}.

Expected behavior

The attribute is changed, and the changeset is valid.

Runtime

Additional context Add any other context about the problem here.

zachdaniel commented 4 months ago

Any modifications of attributes that happen before the call to build the changeset for an action are treated as potentially from input. This is by design although it can be inconvenient at times. The changeset must be first validated for the action, and then attributes can be force changed ( or it can be done in hooks).

moxley commented 4 months ago

Ah yes, I got that backwards. Thanks!