Skip to content

Latest commit

 

History

History
125 lines (95 loc) · 3.42 KB

README.md

File metadata and controls

125 lines (95 loc) · 3.42 KB

Ecto state machine

travis ci badge badge

This package allows to use finite state machine pattern in Ecto. Specify:

and go:

defmodule User do
  use Web, :model

  use EctoStateMachine,
    states: [:unconfirmed, :confirmed, :blocked, :admin],
    events: [
      [
        name:     :confirm,
        from:     [:unconfirmed],
        to:       :confirmed,
        callback: fn(model) -> Ecto.Changeset.change(model, confirmed_at: Ecto.DateTime.utc) end # yeah you can bring your own code to these functions.
      ], [
        name:     :block,
        from:     [:confirmed, :admin],
        to:       :blocked
      ], [
        name:     :make_admin,
        from:     [:confirmed],
        to:       :admin
      ]
    ]

  schema "users" do
    field :state, :string, default: "unconfirmed"
  end
end

now you can do:

user = Repo.get_by(User, id: 1)

# Create changeset transition user state to "confirmed". We can make him admin!
confirmed_user = User.confirm(user)     # =>

# We can validate ability to change user's state
User.can_confirm?(confirmed_user)       # => false
User.can_make_admin?(confirmed_user)    # => true

# Create changeset transition user state to "admin"
admin = User.make_admin(confirmed_user)

# Store changeset to the database
Repo.update(admin)                      


# List all possible states
# If column isn't `:state`, function name will be prefixed. IE,
# for column `:rules` function name will be `rules_states`
User.states # => [:unconfirmed, :confirmed, :blocked, :admin]

# List all possible events
# If column isn't `:state`, function name will be prefixed. IE,
# for column `:rules` function name will be `rules_events`
User.events # => [:confirm, :block, :make_admin]

You can check out whole test/dummy directory to inspect how to organize sample app.

Installation

If available in Hex, the package can be installed as:

  1. Add ecto_state_machine to your list of dependencies in mix.exs:

    def deps do [{:ecto_state_machine, "~> 0.1.0"}] end

Custom column name

ecto_state_machine uses state database column by default. You can specify column option to change it. Like this:

defmodule Dummy.User do
  use Dummy.Web, :model

  use EctoStateMachine,
    column: :rules,
    # bla-bla-bla
end

Now your state will be stored into rules column.

Contributions

  1. Install dependencies mix deps.get
  2. Setup your config/test.exs & config/dev.exs
  3. Run migrations mix ecto.migrate & MIX_ENV=test mix ecto.migrate
  4. Develop new feature
  5. Write new tests
  6. Test it: mix test
  7. Open new PR!

Roadmap to 1.0

  • Cover by tests
  • Custom db column name
  • Validation method for changeset indicates its value in the correct range
  • Initial value
  • CI
  • Add status? methods
  • Introduce it at elixir-radar and my blog
  • Custom error messages for changeset (with translations by gettext ability)
  • Rely on last versions of ecto & elixir
  • Write dedicated module instead of requiring everything into the model
  • Write bang! methods which are raising exception instead of returning invalid changeset
  • Rewrite spaghetti description in README