AshReferentialActions. Changes. EnsureTargetLive
(ash_referential_actions v0.1.0)
Copy Markdown
View Source
Runtime guard added to every create and update action of an
resource that declares restrict or nilify: writing the foreign key is rejected
unless the target exists and is live.
Without this, a user could be pointed at an already-archived (or, on data layers without foreign keys, missing) target — a ghost reference the destroy-side guard can never prevent, since it only fires on the target.
The check runs in two hooks:
before_action— catches direct attribute input early, before any work is done.after_action— re-checks the foreign keys that actually changed on the result record, catching values set afterbefore_action(notablymanage_relationship, which applies belongs_to keys in its own hooks). On transactional data layers the error rolls the write back; on non-transactional layers (e.g. ETS) the error is returned but the write is not undone — the same caveat as any after-action validation there.
The lookup takes a FOR SHARE lock on the target row where the data layer
supports one, so a concurrent archive of that target must wait: either it
commits first and this check sees the archived row, or this write commits
first and the archive's own guard sees this user. Without lock support
(e.g. ETS) the check stays a plain application-level read.
The target is looked up via the referential relationship's declared
read_action (or the referenced resource's primary read — a verifier rejects a
filtered primary read as the default), so action-level read filters cannot
silently hide a live target; archival's global filter still applies, so an
archived target counts as not live.