Variants
A variant captures a named cluster of attribute, association, or transient changes that you can layer onto a factory on demand.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Variants apply through every build strategy — build, create,
build-stubbed, and attributes-for — and through the *-list / *-pair
helpers.
Applying variants at build time
Pass variant names as positional arguments to any build strategy:
1 2 3 4 | |
The same positional form works for the list helpers:
1 2 | |
Multiple variants apply left-to-right
When several variants set the same attribute, the last one wins:
1 2 3 4 5 6 7 8 9 | |
Non-overlapping attributes from each variant are preserved.
What a variant can contain
A variant block is a mini factory body. It can declare any of:
- Static or dynamic attributes that override the factory's defaults.
- Associations via
.association: 'name', :factory<...>. - Transient attributes via
.transient: { ... }, which the rest of the variant (or the original factory body) can read. - Callbacks via
.after: 'build', { ... }/.before: 'create', { ... }/.after: 'create', { ... }/.after: 'stub', { ... }. Variant callbacks fire after the factory's own callbacks for the same event. See the Callbacks page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Variants referencing other variants
A variant can apply another variant by bare name. Cycles are detected and short-circuited, so two variants can safely reference each other:
1 2 3 4 5 6 7 8 9 | |
Composing a factory entirely from variants
Reference variants by bare name in a factory body to layer them in at definition time:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
The same form works for global variants, so a top-level trait can be reused across many factories.
Variant inheritance
A child factory inherits its parent's variants. Either pre-apply them in the child body, or pass them at build time:
1 2 3 4 5 6 7 8 9 10 11 12 | |
See the Inheritance page for the full chain rules.
Parameterised variants
Combine a variant with a transient default to give callers a knob:
1 2 3 4 5 6 7 8 9 10 11 | |
The transient is excluded from attributes-for and never reaches the model
constructor.
Global variants
A variant declared at the top of a define block — without a
surrounding factory — is global. Any factory can apply it, by name at
build time or as a bare reference in its body:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
ORM::Factory.variants returns the registered global variants. Redefining a
global variant raises X::ORM::Factory::DuplicateVariant; ORM::Factory.reload
clears them along with everything else.
variants-for-enum
variants-for-enum declares one variant per value, each one setting the named
attribute to its value:
1 2 3 4 5 6 7 8 9 | |
The value list is explicit; no ORM enum reflection is required.
Automatic enum variants
When a factory's class is an ORM::ActiveRecord model that declares an enum,
the enum's values become variants automatically, with no variants-for-enum
call. Given a model:
1 2 3 4 5 | |
each enum value is a variant that sets the enum attribute to that value:
1 2 3 4 5 6 7 | |
An explicitly declared variant of the same name wins over the derived one. The
behaviour is governed by the automatically-define-enum-variants toggle (on by
default); see Configuration. It applies only to AR models
with enums, so factories for other classes are unaffected.
Errors
- An unknown variant at build time raises
X::ORM::Factory::UnknownVariant. - Defining a variant twice in the same factory raises
X::ORM::Factory::DuplicateVariant. - Defining a global variant twice raises
X::ORM::Factory::DuplicateVariant. - A bare variant reference passed arguments raises
X::ORM::Factory::UsageError— only attribute setters take arguments.