Whatwasit v0.1.0 Whatwasit

Track changes on Ecto Models.

Whatwasit is a package for tracking changes to your project’s Ecto models for auditing or versioning. Keep track of each change to your model and who made the change. Deletes can be tracked too.

Simply add a 2 line change to each model you would like tracked and a version record will be inserted into the database for each change.

defmodule MyProject.Post do
  use MyProject.Web, :model
  use Whatwasit.Schema     # add this

  schema "posts" do
    field :title, :string
    field :body, :string
    timestamps
  end

  def changeset(model, params \ %{}) do
    model
    |> cast(params, ~w(title body))
    |> validate_required(~w(title body)a)
    |> prepare_version    # add this
  end
end

Pass a changeset into Repo.delete and a version record will be inserted into the database when a model is deleted.

defmodule MyProject.PostController do
  # ...
  def delete(conn, %{"id" => id}) do
    changeset = Repo.get!(Post, id)
    |> Post.changeset(%{})

    Repo.delete!(changeset)

    conn
    |> put_flash(:info, "Post deleted successfully.")
    |> redirect(to: post_path(conn, :index))
  end
end

You can also track who made the change with a few extra changes.

defmodule MyProject.Post do
  use MyProject.Web, :model
  use Whatwasit.Schema
  # ...
  def changeset(model, params \ %{}, opts \ []) do
    model
    |> cast(params, ~w(title body))
    |> validate_required(~w(title body)a)
    |> prepare_version(opts)
  end
end

defmodule Admin.PostController do
  # ...

  def update(conn, %{"id" => id, "post" => post_params}) do
    post = Repo.get!(Post, id)
    changeset = Post.changeset(post, post_params, whodoneit: Coherence.current_user(conn))
    case Repo.update(changeset) do
      {:ok, post} ->
        conn
        |> put_flash(:info, "Post updated successfully.")
        |> redirect(to: post_path(conn, :show, post))
      {:error, changeset} ->
        render(conn, "edit.html", post: post, changeset: changeset)
    end
  end

  def delete(conn, %{"id" => id}) do
    changeset = Repo.get!(Post, id)
    |> Post.changeset(%{}, whodoneit: Coherence.current_user(conn))

    Repo.delete!(changeset)

    conn
    |> put_flash(:info, "Post deleted successfully.")
    |> redirect(to: post_path(conn, :index))
  end
end

Retrieve the versions for a specific record:

iex(4)> post = MyProject.Repo.get MyProject.Post, 9

%MyProject.Post{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">,
 body: "The answer is 42", id: 9,
 inserted_at: #Ecto.DateTime<2016-07-22 01:49:25>, title: "What's the Question",
 updated_at: #Ecto.DateTime<2016-07-22 01:49:55>}

iex(5)> MyProject.Post.versions post

[%MyProject.Post{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, body: "42",
  id: 9, inserted_at: "2016-07-22T01:49:25", title: "The Answer",
  updated_at: "2016-07-22T01:49:25"}]