Model Attributes
Ormed models support attribute metadata that affects:
Prerequisites
What You’ll Learn
- How mass-assignment rules (
fillable,guarded) are enforced - How visibility (
hidden,visible) affects serialization - How attribute metadata connects to casting behavior
Step Outcome
By the end of this page, you should be able to:
-
Safely accept trusted/untrusted input with
fillvsforceFill -
Control serialized output fields for API/web responses
-
Use accessors/mutators without breaking tracked model behavior
-
Mass assignment (
fill,fillIfAbsent,forceFill) -
Serialization (
toArray,toJson) -
Casting (see Models → Casting)
These APIs are designed for tracked models (the generated $Model types) and instances returned by queries. Plain user-defined model instances are immutable and typically not used for mass assignment.
Define metadata
Attribute metadata can be declared at the model level, and optionally overridden per-field.
(
table: 'accounts',
fillable: ['email', 'name'],
guarded: ['is_admin'],
hidden: ['password_hash'],
visible: ['password_hash'],
appends: ['display_name'],
)
class Account extends Model<Account> {
const Account({
required this.id,
required this.email,
required this.passwordHash,
this.name,
this.isAdmin = false,
});
(isPrimaryKey: true, autoIncrement: true)
final int id;
final String email;
(columnName: 'password_hash')
final String passwordHash;
final String? name;
(columnName: 'is_admin', guarded: true)
final bool isAdmin;
Mass assignment
Mass assignment takes a Map<String, Object?> keyed by column names and applies fillable/guarded rules.
void massAssignmentExample() {
final account = $Account(id: 1, email: 'a@example.com', passwordHash: 'hash');
// Only fillable columns are applied; guarded columns are discarded.
account.fill({'email': 'new@example.com', 'is_admin': true});
// Enable strict mode to throw instead of silently discarding.
try {
account.fill({'is_admin': true}, strict: true);
} on MassAssignmentException {
// Handle mass assignment failures.
}
// Bypass guards for trusted code paths.
account.forceFill({'is_admin': true});
}
Notes:
fill(...)defaults tostrict: false(guarded keys are discarded).- Set
strict: trueto throw aMassAssignmentExceptionwhen a guarded key is present. - Use
forceFill(...)only for trusted/internal flows. fill/fillIfAbsent/forceFillaccept tracked models, DTOs, and partials in addition to maps.- Map keys can be Dart field names or column names (they are normalized).
Default to fill(...) for request payloads, and reserve forceFill(...) for trusted internal flows.
Serialization (hidden / visible)
toArray() / toJson() honor hidden by default. To include hidden values you must set includeHidden: true, and the column must also be listed in visible.
Map<String, Object?> serializationExample() {
final account = $Account(id: 1, email: 'a@example.com', passwordHash: 'hash');
// Hidden columns are excluded.
final safe = account.toArray();
// Hidden columns can be included, but only when they're explicitly visible.
final internal = account.toArray(includeHidden: true);
return {'safe': safe, 'internal': internal};
}
Keep sensitive values (password, secrets, tokens) hidden by default, even for internal APIs.
Accessors and mutators
Accessors let you transform attribute reads, while mutators normalize values when they are assigned. Define them as static members on the model, similar to query scopes.
(attribute: 'display_name')
static String displayName(Account model, Object? _) =>
model.name ?? model.email;
(attribute: 'email')
static String normalizeEmail(Account model, String? value) =>
value?.trim().toLowerCase() ?? model.email;
Accessors and mutators must be declared as static. The generator exposes them
on tracked models via extensions, so you can read tracked.displayName and call
tracked.normalizeEmail('User@Example.com'). Accessors apply when using
getAttribute(...) and serialization (toArray, toJson). Mutators apply when
using setAttribute(...), fill(...), or tracked setters. Use
getRawAttribute(...) / setRawAttribute(...) to bypass accessors/mutators.
Appends (computed attributes)
Use appends to include computed attributes in toArray() / toJson() output.
Map<String, Object?> appendsExample() {
final account = $Account(
id: 2,
email: 'User@Example.com',
passwordHash: 'hash',
name: 'User Name',
);
return account.toArray();
}
Verify Attribute Rules
Add tests for:
- Guarded key rejection/ignore behavior.
- Hidden/visible serialization output.
- Accessor/mutator behavior on tracked instances.