Class DS.RootState

State

Each record has a currentState property that explicitly tracks what
state a record is in at any given time. For instance, if a record is
newly created and has not yet been sent to the adapter to be saved,
it would be in the root.loaded.created.uncommitted state. If a
record has had local modifications made to it that are in the
process of being saved, the record would be in the
root.loaded.updated.inFlight state. (This state paths will be
explained in more detail below.)

Events are sent by the record or its store to the record's
currentState property. How the state reacts to these events is
dependent on which state it is in. In some states, certain events
will be invalid and will cause an exception to be raised.

States are hierarchical and every state is a substate of the
RootState. For example, a record can be in the
root.deleted.uncommitted state, then transition into the
root.deleted.inFlight state. If a child state does not implement
an event handler, the state manager will attempt to invoke the event
on all parent states until the root state is reached. The state
hierarchy of a record is described in terms of a path string. You
can determine a record's current state by getting the state's
stateName property:

1
2

record.get('currentState.stateName');
//=> "root.created.uncommitted"

The hierarchy of valid states that ship with ember data looks like
this:

The DS.Model states are themselves stateless. What that means is
that, the hierarchical states that each of those points to is a
shared data structure. For performance reasons, instead of each
record getting its own copy of the hierarchy of states, each record
points to this global, immutable shared instance. How does a state
know which record it should be acting on? We pass the record
instance into the state's event handlers as the first argument.

The record passed as the first parameter is where you should stash
state about the record if needed; you should never store data on the state
object itself.

Events and Flags

A state may implement zero or more events and flags.

Events

Events are named functions that are invoked when sent to a record. The
record will first look for a method with the given name on the
current state. If no method is found, it will search the current
state's parent, and then its grandparent, and so on until reaching
the top of the hierarchy. If the root is reached without an event
handler being found, an exception will be raised. This can be very
helpful when debugging new features.

Here's an example implementation of a state with a myEvent event handler:

Note that an optional parameter can be sent to a record's send() method,
which will be passed as the second parameter to the event handler.

Events should transition to a different state if appropriate. This can be
done by calling the record's transitionTo() method with a path to the
desired state. The state manager will attempt to resolve the state path
relative to the current state. If no state is found at that path, it will
attempt to resolve it relative to the current state's parent, and then its
parent, and so on until the root is reached. For example, imagine a hierarchy
like this:

If we are currently in the uncommitted state, calling
transitionTo('inFlight') would transition to the created.inFlight state,
while calling transitionTo('updated.inFlight') would transition to
the updated.inFlight state.

Remember that only events should ever cause a state transition. You should
never call transitionTo() from outside a state's event handler. If you are
tempted to do so, create a new event and send that to the state manager.

Flags

Flags are Boolean values that can be used to introspect a record's current
state in a more user-friendly way than examining its state path. For example,
instead of doing this: