Uploadex
Uploadex is an Elixir library for handling uploads using Ecto and Arc.
Documentation can be found at https://hexdocs.pm/uploadex.
Installation
The package can be installed by adding uploadex to your list of dependencies in mix.exs:
def deps do
[
{:uploadex, "~> 0.1.2"}
]
endUsage
This library is built on top of Arc, so you can configure it normally. To use the default configuration, storing to the disk, no configuration is needed.
Then, define your uploader:
defmodule MyApp.MyUploader do
use Uploadex.Definition,
repo: MyApp.Repo
## Functions required for Uploadex.Definition
def base_directory do
Path.join(:code.priv_dir(:my_app), "static/")
end
def get_files(%MyApp.User{photo: photo}), do: photo
# For this example, we assume company has_many :photos, and each photo has a file field.
# For this to work properly, we will need cast_assoc :photos when inserting/updating a company.
def get_files(%MyApp.Company{} = company) do
company
|> MyApp.Repo.preload(:photos)
|> Map.get(:photos)
|> Enum.map(& &1.file)
end
## We can also define the functions for Arc.Definition here
def storage_dir(_version, {_file, %User{id: user_id}}) do
Path.join(base_directory(), "/uploads/users/\#{user_id}")
end
def storage_dir(_version, {_file, %Company{id: id}}) do
Path.join(base_directory(), "/uploads/companies/\#{id}")
end
endIn your schema, use the Ecto Type Uploadex.Upload:
schema "users" do
field :name, :string
field :photo, Uploadex.Upload
end
# No special cast is needed, and casting does not have any side effects.
def create_changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:name, :photo])
endNow, you can use the Uploadex functions to handle your records with their files:
defmodule MyApp.Accounts do
alias MyApp.Accounts.User
alias MyApp.MyUploader
def create_user(attrs) do
%User{}
|> User.create_changeset(attrs)
|> Uploadex.create_with_file(MyUploader)
end
def update_user(%User{} = user, attrs) do
user
|> User.update_changeset(attrs)
|> Uploadex.update_with_file(user, MyUploader)
end
def delete_user(%User{} = user) do
user
|> Ecto.Changeset.change()
|> Uploadex.delete_with_file(MyUploader)
end
endFor more flexibility, you can use the Files module (or even the arc functions) directly.
Motivation
Even though there already exists a library to integrate Arc with Ecto (https://github.com/stavro/arc_ecto), this library was created because:
- arc_ecto does not support upload of binary files
- Uploadex makes it easier to deal with records that contain files without having to manage those files manually on every operation
- Using uploadex, the changeset operations have no side-effects and no special casting is needed