Errors
ORM::ActiveRecord exposes two complementary error surfaces:
- Typed exceptions for failure modes that callers want to
try { … CATCH { … } }around — things like a missing row, an invalid record, or an irreversible migration. - A per-record
errorscollection that captures validation failures without throwing, so the caller can inspect every problem on a record at once.
The exceptions live in:
1 | |
The collection is what record.errors returns. It is documented in The errors collection at the bottom of this page.
Each exception is a regular Raku Exception, so the usual try { … CATCH { when … } }
idiom applies. The table below summarises which methods raise which exception;
the sections that follow document the attributes each one carries.
| Exception | Raised by |
|---|---|
X::RecordNotFound |
find, find-by-bang |
X::RecordInvalid |
save-bang, update-bang, create-bang |
X::ReadOnlyRecord |
save / update / destroy / delete on a record from a readonly relation |
X::IrreversibleMigration |
self.irreversible-migration inside a migration down |
X::StrictValidationFailed |
validator declared with :strict — see Validator Options » strict |
X::RecordNotFound
Raised when a finder can prove the row does not exist.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
find($id) always raises on a miss. find-by(%conditions) returns Nil
instead — use find-by-bang(%conditions) if you want the loud variant.
X::RecordInvalid
Raised by the -bang persistence methods when validations fail. The
exception carries both the failing record and a list of human-readable
messages built from the model's errors.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
save / update / create (without -bang) return False on validation
failure instead of raising — inspect .errors on the record to see what went
wrong. See Persistence for the full quiet-vs-loud
breakdown.
X::ReadOnlyRecord
Raised when any write method (save, update, destroy, delete) is
invoked on a record that was fetched through a readonly relation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Clear the flag with unscope(:readonly) on the relation before fetching if
you want a writable record. See Aggregation » readonly.
X::IrreversibleMigration
Raised from inside a migration down to signal that the change can't be
rolled back automatically. The ar runner catches it, reports which file
fired, and aborts the rollback.
1 2 3 4 5 6 7 8 9 10 11 | |
self.irreversible-migration is a one-liner that constructs and throws the
exception — it exists so the intent reads as a migration step rather than
manual exception plumbing. See Migrations » Irreversible migrations.
X::StrictValidationFailed
Raised from is-valid / is-invalid when a validator declared with :strict
fails — instead of pushing onto errors, the chain aborts and this exception
carries the underlying message and the failing attribute name.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
See Validator Options » strict for the declaration syntax.
The errors collection
Every model instance carries an errors object — an instance of
ORM::ActiveRecord::Errors::Errors — that validators populate during
is-valid / is-invalid. The collection mirrors Rails' ActiveModel::Errors
API so the same patterns (add, delete, clear, where, details,
full-messages, is-added, group-by-attribute, merge, …) work without
translation.
Each entry is an ORM::ActiveRecord::Errors::Error carrying:
| Field | Meaning |
|---|---|
attribute |
Attribute the error is attached to ('base' for record-level errors) |
type |
Short symbolic kind (e.g. 'blank', 'taken', 'greater-than') |
message |
Human-readable failure message (already interpolated) |
options |
Hash of options preserved from the add call (e.g. count => 5) |
Adding errors
add is the primary way to append an error from user code or from a custom
validator. The second argument is the error type; pass :message to override
the rendered text, and any extra named options interpolate into the template.
1 2 3 4 | |
Pre-built Error instances (for example, when copying errors from one record
to another) can be appended with import:
1 | |
Removing errors
1 2 3 | |
Reading errors
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Indexed access ($record.errors[0]) and FALLBACK access by attribute name
($record.errors.email) are both supported. The FALLBACK form returns a
sequence of messages for that attribute, so it composes with [0] or
stringification: $record.errors.email[0] eq 'must be present'.
Looking for specific errors
1 2 3 4 5 6 | |
Merging errors between records
merge appends another record's errors onto this one. Useful when bubbling
errors up from an associated record.
1 | |
Error types emitted by built-in validators
| Validator | Type(s) recorded |
|---|---|
:presence |
blank |
length (max) |
too-long (carries :count) |
length (min) |
too-short (carries :count) |
length (is / in) |
wrong-length (carries :count when is) |
:acceptance |
accepted |
:confirmation |
confirmation |
inclusion |
inclusion |
exclusion |
exclusion |
format |
invalid |
numericality / comparison |
greater-than, greater-than-or-equal-to, less-than, less-than-or-equal-to, equal-to, other-than (each carries :count) |
uniqueness |
taken |
validates-associated |
invalid |
automatic belongs-to presence |
blank |
dependent: :restrict_with_error |
restrict-dependent-destroy |