AshGrant.Changes.ResolveArgument (AshGrant v0.14.1)

Copy Markdown View Source

Runtime change that lazily populates an action argument from the record's own relationships.

Installed automatically by AshGrant.Transformers.AddArgumentResolvers when a resource declares resolve_argument in its ash_grant block. Users rarely reference this module directly.

Options

  • :name — argument name to set
  • :path — list of atoms walking relationships to a leaf attribute (e.g. [:order, :center_id], [:order, :customer, :organization_id]). Intermediate keys are belongs_to relationships; the last is an attribute.
  • :scopes_needing — list of scope atoms whose resolved filter references ^arg(<name>). Injected by the transformer at compile time.

Runtime contract

If the actor is nil, or none of the actor's permissions (as returned by the resource's configured AshGrant.PermissionResolver) use a scope in :scopes_needing, the change is a no-op — no DB load is performed.

If the resource has no resolver configured, or the resolver raises/returns an unexpected shape, the change conservatively resolves the argument rather than skipping — otherwise production actors (Ash resource structs that carry no literal :permissions field) would silently bypass the resolver.

Otherwise, the change resolves the path:

  • create: read the first-hop foreign key from the changeset's attributes, fetch the head record, then walk the remaining path keys through loaded relationships.
  • update/destroy: load the relationship path on changeset.data, then read the leaf attribute.

If any intermediate value is nil or the path cannot be resolved (e.g., the referenced record was deleted), the change returns the changeset unchanged — the scope will then evaluate against a nil argument and typically fail closed (authorization denied).

Multi-tenancy

The changeset's :tenant is forwarded to the internal Ash.get!/Ash.load! calls so that resources along from_path using attribute multitenancy can be fetched correctly. Without this, those fetches would raise, be rescued, and leave the argument unset — causing the scope to evaluate to false.