Skip to content

Commit 2978771

Browse files
committed
Allow validating uploads in handle_changes
1 parent 7d96a89 commit 2978771

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

lib/upload/multi.ex

+23-9
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,12 @@ defmodule Upload.Multi do
8383
8484
## Example
8585
86-
```elixir
87-
defp insert_person(changeset) do
88-
Ecto.Multi.new()
89-
|> Ecto.Multi.insert(:person, changeset)
90-
|> Upload.Multi.handle_changes(:upload_avatar, :person, changeset, :avatar, key_function: &key_function/1)
91-
|> Repo.transaction()
92-
end
93-
```
86+
defp insert_person(changeset) do
87+
Ecto.Multi.new()
88+
|> Ecto.Multi.insert(:person, changeset)
89+
|> Upload.Multi.handle_changes(:upload_avatar, :person, changeset, :avatar, key_function: &key_function/1)
90+
|> Repo.transaction()
91+
end
9492
9593
## Options
9694
@@ -99,6 +97,7 @@ defmodule Upload.Multi do
9997
"""
10098
def handle_changes(multi, name, subject, changeset, field, opts \\ []) do
10199
key_function = key_function_from_opts(opts)
100+
validate_function = validate_function_from_opts(opts)
102101

103102
Multi.run(multi, name, fn repo, changes ->
104103
# This code is run after the record in inserted in the Multi pipeline.
@@ -120,6 +119,7 @@ defmodule Upload.Multi do
120119
key_function.(record)
121120
end
122121
)
122+
|> validate_function.(field)
123123

124124
record_changeset.changes
125125
|> Enum.reduce(Ecto.Multi.new(), fn {changed_field, change}, multi ->
@@ -130,11 +130,25 @@ defmodule Upload.Multi do
130130
|> repo.transaction()
131131
|> case do
132132
{:ok, result} -> {:ok, result["#{field}_attach_blob"]}
133-
error -> error
133+
{:error, _stage, changeset, _rest} -> {:error, changeset}
134134
end
135135
end)
136136
end
137137

138+
defp validate_function_from_opts(opts) do
139+
case Keyword.get(opts, :validate) do
140+
nil ->
141+
fn changeset, _field -> changeset end
142+
143+
validate_function when is_function(validate_function, 2) ->
144+
validate_function
145+
146+
unexpected ->
147+
raise ArgumentError,
148+
"validate function must be a function of arity 2. Got #{inspect(unexpected)}"
149+
end
150+
end
151+
138152
defp key_function_from_opts(opts) do
139153
case Keyword.get(opts, :key_function) do
140154
nil ->

test/upload/multi_test.exs

+20-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,25 @@ defmodule Upload.MultiTest do
1212
@path "test/fixtures/image.jpg"
1313
@upload %Plug.Upload{path: @path, filename: "image.jpg"}
1414

15+
describe "handle_changes" do
16+
test "can validate changes" do
17+
changeset = Person.changeset(%Person{}, %{avatar: "test/fixtures/test.txt"})
18+
19+
{:error, _, changeset, _} =
20+
Ecto.Multi.new()
21+
|> Ecto.Multi.insert(:insert_person, changeset)
22+
|> Upload.Multi.handle_changes(:upload_avatar, :insert_person, changeset, :avatar,
23+
key_function: &key_function/1,
24+
validate: fn changeset, field ->
25+
Upload.Changeset.validate_attachment_type(changeset, field, allow: ["image/jpeg"])
26+
end
27+
)
28+
|> Repo.transaction()
29+
30+
assert errors_on(changeset)[:avatar] == ["is not a supported file type"]
31+
end
32+
end
33+
1534
test "upload/3" do
1635
assert {:ok, person} = insert_person(%{avatar: @upload})
1736
assert person.avatar_id
@@ -236,9 +255,7 @@ defmodule Upload.MultiTest do
236255
Ecto.Multi.new()
237256
|> Ecto.Multi.insert(:insert_person, changeset)
238257
|> Upload.Multi.handle_changes(:person, :insert_person, changeset, :avatar,
239-
key_function: fn user ->
240-
"uploads/users/#{user.id}/avatar"
241-
end,
258+
key_function: &key_function/1,
242259
canned_acl: :public
243260
)
244261
|> Repo.transaction()

0 commit comments

Comments
 (0)