Skip to content

Commit

Permalink
logic is complete detailed tests are missing
Browse files Browse the repository at this point in the history
  • Loading branch information
izelnakri committed Mar 16, 2017
1 parent c825c1b commit 9d9ba81
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 20 deletions.
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,22 +160,26 @@ PaperTrail.insert(new_user_changeset, origin: "facebook_registration")
```

### Originator relationships
You can specify setter/originator relationship to paper_trail versions with ```originator_id``` assignment. This feature is only possible by specifying `:originator` keyword list for your application configuration:
You can specify setter/originator relationship to paper_trail versions with ```originator``` assignment. This feature is only possible by specifying `:originator` keyword list for your application configuration:

```elixir
# in your config/config.exs
config :paper_trail, originator: [name: :user, model: YourApp.User]
# For most applications originator should be the user since models can be updated/created/deleted by several users.
```

Then originator name could be used for querying and preloading however originator setting must be done via originator_id:
Then originator name could be used for querying and preloading. Originator setting must be done via ```:originator``` or originator name that is defined in the paper_trail configuration:

```elixir
user = create_user()
PaperTrail.insert(changeset, originator_id: user.id)
{:ok, result} = PaperTrail.update(edit_changeset, originator_id: user.id)
# all these set originator_id's for the version records
PaperTrail.insert(changeset, originator: user)
{:ok, result} = PaperTrail.update(edit_changeset, originator: user)
# or you can use :user instead of :originator if this is your config:
# paper_trail originator: [name: :user, model: YourApplication.User]
{:ok, result} = PaperTrail.update(edit_changeset, user: user)
result[:version] |> Repo.preload(:user) |> Map.get(:user) # we can access the user who made the change from the version thanks to originator relationships!
PaperTrail.delete(edit_changeset, originator_id: user.id)
PaperTrail.delete(edit_changeset, user: user)
```

Also make sure you have the foreign-key constraint in the database and in your version migration file.
Expand Down Expand Up @@ -263,7 +267,7 @@ edited_company = Company.changeset(company, %{name: "Acme Inc."}) |> PaperTrail.
Additionally, you can put a null constraint on ```origin``` column, you should always put an ```origin``` reference to describe who makes the change. This is important for big applications because a model can change from many sources.

### Storing version meta data
You might want to add some meta data that doesn't belong to ``originator_id`` and ``origin`` fields. Such data could be stored in one object named ```meta``` in paper_trail versions. Meta field could be passed as the second optional parameter to PaperTrail.insert/2, PaperTrail.update/2, PaperTrail.delete/2 functions:
You might want to add some meta data that doesn't belong to ``originator`` and ``origin`` fields. Such data could be stored in one object named ```meta``` in paper_trail versions. Meta field could be passed as the second optional parameter to PaperTrail.insert/2, PaperTrail.update/2, PaperTrail.delete/2 functions:

```elixir
company = Company.changeset(%Company{}, %{name: "Acme Inc."})
Expand Down
2 changes: 1 addition & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use Mix.Config

config :paper_trail, ecto_repos: [PaperTrail.Repo]

config :paper_trail, repo: PaperTrail.Repo
config :paper_trail, repo: PaperTrail.Repo, originator: [name: :user, model: User]

config :paper_trail, PaperTrail.Repo,
adapter: Ecto.Adapters.Postgres,
Expand Down
30 changes: 23 additions & 7 deletions lib/paper_trail.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ defmodule PaperTrail do
alias Ecto.Multi
alias PaperTrail.Version

@repo PaperTrail.RepoClient.repo
@repo PaperTrail.RepoClient.repo()
@originator PaperTrail.RepoClient.originator()
@client PaperTrail.RepoClient

@doc """
Expand Down Expand Up @@ -47,7 +48,7 @@ defmodule PaperTrail do
@doc """
Inserts a record to the database with a related version insertion in one transaction
"""
def insert(changeset, options \\ [origin: nil, meta: nil, originator_id: nil]) do
def insert(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do
case @client.strict_mode() do
true ->
transaction = Multi.new
Expand Down Expand Up @@ -98,7 +99,7 @@ defmodule PaperTrail do
@doc """
Updates a record from the database with a related version insertion in one transaction
"""
def update(changeset, options \\ [origin: nil, meta: nil, originator_id: nil]) do
def update(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do
case @client.strict_mode() do
true ->
transaction = Multi.new
Expand Down Expand Up @@ -145,7 +146,7 @@ defmodule PaperTrail do
@doc """
Deletes a record from the database with a related version insertion in one transaction
"""
def delete(struct, options \\ [origin: nil, meta: nil, originator_id: nil]) do
def delete(struct, options \\ [origin: nil, meta: nil, originator: nil]) do
transaction = Multi.new
|> Multi.delete(:model, struct)
|> Multi.run(:version, fn %{} ->
Expand All @@ -161,34 +162,49 @@ defmodule PaperTrail do
end

defp make_version_struct(%{event: "insert"}, model, options) do
originator_ref = options[@originator[:name]] || options[:originator]
originator_id = case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end
%Version{
event: "insert",
item_type: model.__struct__ |> Module.split |> List.last,
item_id: model.id,
item_changes: serialize(model),
originator_id: options[:originator_id],
originator_id: originator_id,
origin: options[:origin],
meta: options[:meta]
}
end
defp make_version_struct(%{event: "update"}, changeset, options) do
originator_ref = options[@originator[:name]] || options[:originator]
originator_id = case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end
%Version{
event: "update",
item_type: changeset.data.__struct__ |> Module.split |> List.last,
item_id: changeset.data.id,
item_changes: changeset.changes,
originator_id: options[:originator_id],
originator_id: originator_id,
origin: options[:origin],
meta: options[:meta]
}
end
defp make_version_struct(%{event: "delete"}, model, options) do
originator_ref = options[@originator[:name]] || options[:originator]
originator_id = case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end
%Version{
event: "delete",
item_type: model.__struct__ |> Module.split |> List.last,
item_id: model.id,
item_changes: serialize(model),
originator_id: options[:originator_id],
originator_id: originator_id,
origin: options[:origin],
meta: options[:meta]
}
Expand Down
7 changes: 4 additions & 3 deletions test/paper_trail_strict_mode_test.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# test one with user:, one with originator
defmodule PaperTrailStrictModeTest do
use ExUnit.Case

Expand Down Expand Up @@ -32,7 +33,7 @@ defmodule PaperTrailStrictModeTest do

test "creating a company creates a company version with correct attributes" do
user = create_user()
{:ok, result} = create_company_with_version(@create_company_params, originator_id: user.id)
{:ok, result} = create_company_with_version(@create_company_params, originator: user)

company_count = Company.count()
version_count = Version.count()
Expand Down Expand Up @@ -78,7 +79,7 @@ defmodule PaperTrailStrictModeTest do
user = create_user()
{:ok, insert_company_result} = create_company_with_version()
{:ok, result} = update_company_with_version(
insert_company_result[:model], @update_company_params, originator_id: user.id
insert_company_result[:model], @update_company_params, originator: user
)

company_count = Company.count()
Expand Down Expand Up @@ -137,7 +138,7 @@ defmodule PaperTrailStrictModeTest do
{:ok, insert_company_result} = create_company_with_version()
{:ok, update_company_result} = update_company_with_version(insert_company_result[:model])
company_before_deletion = first(Company, :id) |> @repo.one |> serialize
{:ok, result} = PaperTrail.delete(update_company_result[:model], originator_id: user.id)
{:ok, result} = PaperTrail.delete(update_company_result[:model], originator: user)

company_count = Company.count()
version_count = Version.count()
Expand Down
7 changes: 4 additions & 3 deletions test/paper_trail_test.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# test one with user:, one with originator
defmodule PaperTrailTest do
use ExUnit.Case

Expand Down Expand Up @@ -32,7 +33,7 @@ defmodule PaperTrailTest do

test "creating a company creates a company version with correct attributes" do
user = create_user()
{:ok, result} = create_company_with_version(@create_company_params, originator_id: user.id)
{:ok, result} = create_company_with_version(@create_company_params, originator: user)

company_count = Company.count()
version_count = Version.count()
Expand Down Expand Up @@ -76,7 +77,7 @@ defmodule PaperTrailTest do
user = create_user()
{:ok, insert_result} = create_company_with_version()
{:ok, result} = update_company_with_version(
insert_result[:model], @update_company_params, originator_id: user.id
insert_result[:model], @update_company_params, user: user
)

company_count = Company.count()
Expand Down Expand Up @@ -128,7 +129,7 @@ defmodule PaperTrailTest do
{:ok, insert_result} = create_company_with_version()
{:ok, update_result} = update_company_with_version(insert_result[:model])
company_before_deletion = first(Company, :id) |> @repo.one |> serialize
{:ok, result} = PaperTrail.delete(update_result[:model], originator_id: user.id)
{:ok, result} = PaperTrail.delete(update_result[:model], originator: user)

company_count = Company.count()
version_count = Version.count()
Expand Down

0 comments on commit 9d9ba81

Please sign in to comment.