diff --git a/documentation/dsls/DSL:-AshStateMachine.md b/documentation/dsls/DSL:-AshStateMachine.md index fe6a6dd..ddb7a62 100644 --- a/documentation/dsls/DSL:-AshStateMachine.md +++ b/documentation/dsls/DSL:-AshStateMachine.md @@ -24,7 +24,7 @@ Provides tools for defining and working with resource-backed state machines. | [`initial_states`](#state_machine-initial_states){: #state_machine-initial_states .spark-required} | `list(atom)` | | The allowed starting states of this state machine. | | [`deprecated_states`](#state_machine-deprecated_states){: #state_machine-deprecated_states } | `list(atom)` | `[]` | A list of states that have been deprecated but are still valid. These will still be in the possible list of states, but `:*` will not include them. | | [`extra_states`](#state_machine-extra_states){: #state_machine-extra_states } | `list(atom)` | `[]` | A list of states that may be used by transitions to/from `:*`. See the docs on wildcards for more. | -| [`state_attribute`](#state_machine-state_attribute){: #state_machine-state_attribute } | `atom` | `:state` | The attribute to store the state in. | +| [`state_attribute`](#state_machine-state_attribute){: #state_machine-state_attribute } | `atom` | `:state` | The attribute to store the state in. You don't have to declare an attribute yourself, but it is possible. See the tutorial for more information. | | [`default_initial_state`](#state_machine-default_initial_state){: #state_machine-default_initial_state } | `atom` | | The default initial state | diff --git a/documentation/tutorials/getting-started-with-ash-state-machine.md b/documentation/tutorials/getting-started-with-ash-state-machine.md index 398edc4..3d4957b 100644 --- a/documentation/tutorials/getting-started-with-ash-state-machine.md +++ b/documentation/tutorials/getting-started-with-ash-state-machine.md @@ -81,6 +81,47 @@ actions do end ``` +## Declaring a custom state attribute + +By default, a `:state` attribute is created on the resource that looks like this: + +```elixir +attribute :state, :atom do + allow_nil? false + default AshStateMachine.Info.state_machine_initial_default_state(dsl_state) + public? true + constraints one_of: [ + AshStateMachine.Info.state_machine_all_states(dsl_state) + ] +end +``` + +You can change the name of this attribute, without declaring an attribute yourself, like so: + +```elixir +state_machine do + initial_states([:pending]) + default_initial_state(:pending) + state_attribute(:alternative_state) # <-- save state in an attribute named :alternative_state +end +``` + +If you need more control, you can declare the attribute yourself on the resource: + +```elixir +attributes do + attribute :alternative_state, :atom do + allow_nil? false + default :issued + public? true + constraints one_of: [:issued, :sold, :reserved, :retired] + end +end +``` + +Be aware that the type of this attribute needs to be `:atom` or a type created with `Ash.Type.Enum`. Both the `default` and list of values need to be correct! + + ## Making a resource into a state machine The concept of a state machine (in this case a "Finite State Machine"), essentially involves a single `state`, with specified transitions between states. For example, you might have an order state machine with states `[:pending, :on_its_way, :delivered]`. However, you can't go from `:pending` to `:delivered` (probably), and so you want to only allow certain transitions in certain circumstances, i.e `:pending -> :on_its_way -> :delivered`.