Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add delete_attachments to schema #77

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,32 @@ Both public and signed urls will include the timestamp for cache busting, and ar
MyApp.Avatar.url({user.avatar, user}, :thumb, signed: true)
```

### Delete attached file from storage

Attachments can be deleted using `delete_attachments/2` before calling `Repo.delete/1`.

```elixir
defmodule MyApp.User do
# ...

def delete_changeset(data) do
data
|> changeset(%{})
|> delete_attachments(@attachments)
end
end
```

Then, to delete, instead of calling `Repo.delete` from element, do it from deletion
changeset (like when using `Ecto.Changeset.prepare_changes/2`):

```elixir
user
|> MyApp.User.delete_changeset()
|> MyApp.Repo.delete()

```

## License

Copyright 2015 Sean Stavropoulos
Expand Down
3 changes: 2 additions & 1 deletion lib/arc_ecto/definition.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule Arc.Ecto.Definition do
defmodule Module.concat(unquote(definition), "Type") do
@behaviour Ecto.Type
def type, do: Arc.Ecto.Type.type
def definition, do: unquote(definition)
def cast(value), do: Arc.Ecto.Type.cast(unquote(definition), value)
def load(value), do: Arc.Ecto.Type.load(unquote(definition), value)
def dump(value), do: Arc.Ecto.Type.dump(unquote(definition), value)
Expand All @@ -30,7 +31,7 @@ defmodule Arc.Ecto.Definition do
end

def url(f, v, options), do: super(f, v, options)

def delete({%{file_name: file_name, updated_at: _updated_at}, scope}), do: super({file_name, scope})

def delete(args), do: super(args)
Expand Down
20 changes: 20 additions & 0 deletions lib/arc_ecto/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ defmodule Arc.Ecto.Schema do
defmacro __using__(_) do
quote do
import Arc.Ecto.Schema

def delete_attachments(changeset_or_data, fields) do
scope = case changeset_or_data do
%Ecto.Changeset{} -> Ecto.Changeset.apply_changes(changeset_or_data)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scenario works for removing attachment with parent entity. But what if we will add the third case?
When field has changes we could remove attachment from S3 because field would be updated with new attachment without removing parent entity.

%{__meta__: _} -> changeset_or_data
end
Enum.each(fields, &(delete_attachment(scope, &1)))
changeset_or_data
end

defp delete_attachment(scope, field) do
type = __MODULE__.__schema__(:type, field)
definition = type.definition()
value = Map.get(scope, field)
if value do
{value, scope}
|> definition.urls()
|> Enum.each(fn {_size, path} -> definition.delete({path, scope}) end)
end
end
end
end

Expand Down
5 changes: 5 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ defmodule Arc.Ecto.Mixfile do
[app: :arc_ecto,
version: @version,
elixir: "~> 1.0",
elixirc_paths: elixirc_paths(Mix.env),
deps: deps(),

# Hex
Expand All @@ -21,6 +22,10 @@ defmodule Arc.Ecto.Mixfile do
[applications: [:logger, :arc]]
end

# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]

defp description do
"""
An integration with Arc and Ecto.
Expand Down
26 changes: 14 additions & 12 deletions test/schema_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ defmodule ArcTest.Ecto.Schema do
use ExUnit.Case, async: false
import Mock

defmodule DummyDefinition do
use Arc.Definition
use Arc.Ecto.Definition
end
alias ArcTest.Ecto.DummyDefinition

defmodule TestUser do
use Ecto.Schema
Expand Down Expand Up @@ -36,15 +33,12 @@ defmodule ArcTest.Ecto.Schema do
|> cast(params, ~w(first_name)a)
|> cast_attachments(params, ~w(avatar)a)
end
end

setup do
defmodule DummyDefinition do
use Arc.Definition
use Arc.Ecto.Definition
def delete_changeset(user, params) do
user
|> changeset(params)
|> delete_attachments(~w(avatar)a)
end

:ok
end

def build_upload(path) do
Expand All @@ -70,7 +64,7 @@ defmodule ArcTest.Ecto.Schema do
cs = TestUser.changeset(%TestUser{}, %{"avatar" => upload})
assert called DummyDefinition.store({upload, %TestUser{}})
assert cs.valid? == false
assert cs.errors == [avatar: {"is invalid", [type: ArcTest.Ecto.Schema.DummyDefinition.Type]}]
assert cs.errors == [avatar: {"is invalid", [type: DummyDefinition.Type]}]
end

test_with_mock "converts changeset into schema", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:error, :invalid_file} end] do
Expand Down Expand Up @@ -101,4 +95,12 @@ defmodule ArcTest.Ecto.Schema do
changeset = TestUser.path_changeset(%TestUser{}, %{"avatar" => "/path/to/my/file.png"})
assert called DummyDefinition.store({"/path/to/my/file.png", %TestUser{}})
end

test_with_mock "deletes attachments", DummyDefinition, [store: fn({%{__struct__: Plug.Upload, path: "/path/to/my/file.png", file_name: "file.png"}, %TestUser{}}) -> {:ok, "file.png"} end,
urls: fn({%{file_name: "file.png"}, %TestUser{}}) -> %{original: "file.png"} end,
delete: fn({"file.png", %TestUser{}}) -> :ok end] do
upload = build_upload("/path/to/my/file.png")
TestUser.delete_changeset(%TestUser{}, %{"avatar" => upload})
assert called DummyDefinition.delete({"file.png", :_})
end
end
4 changes: 4 additions & 0 deletions test/support/dummy_definition.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule ArcTest.Ecto.DummyDefinition do
use Arc.Definition
use Arc.Ecto.Definition
end