[![Build Status](](
[![Coverage Status](](

# Upload

An opinionated file uploader for Elixir projects.

Upload offers the following features:

* Minimal API
* Sane defaults
* Ecto integration
* Multiple storage adapters

## Installation

If [available in Hex](, the package can be installed
by adding `upload` to your list of dependencies in `mix.exs`:

def deps do
    {:upload, "~> 0.1.0"}

## Usage

Upload a file:

{:ok, upload} = Upload.cast_path("/path/to/file.txt")

# Transfer the upload to storage
{:ok, upload} = Upload.transfer(upload)

# Get the URL for the upload

### Ecto Integration

Add a column to store a logo:

def change do
  alter table(:companies) do
    add :logo, :string

Add a field to your schema:

schema "companies" do
  field :logo, :string

Cast the upload in your changeset:

def changeset(company, attrs \\ %{}) do
  |> cast(attrs, [])
  |> Upload.Ecto.cast_upload(:logo, prefix: ["logos"])

Upload in the controller:

def create(conn, %{"logo" => logo}) do
  changeset = Company.changeset(%Company{}, %{"logo" => logo})

  case Repo.insert(changeset) do
    {:ok, company} ->
      # Insert succeeded. Now, you can get the URL:

    {:error, changeset} ->
      # You know the drill.

### Serving static files

In order to serve the files, you'll need to setup `Plug.Static`.

If you're using Phoenix, you can add this line to `endpoint.ex`:

plug Plug.Static, at: "/", from: :your_app, gzip: false, only: ~w(uploads)

## Configuration

For now, there are four adapters:

* `Upload.Adapters.Local` - Save files to your local filesystem.
* `Upload.Adapters.S3` - Save files to Amazon S3.
* `Upload.Adapters.Fake` - Don't actually save the files at all.
* `Upload.Adapters.Test` - Keep uploaded files in state, so that you can assert.

### `Upload.Adapters.Local`

Out of the box, `Upload` is ready to go with some sane defaults (for development, at least).

Here are the default values:

config :upload, Upload,
  adapter: Upload.Adapters.Local

config :upload, Upload.Adapters.Local,
  storage_path: "priv/static/uploads",
  public_path: "/uploads"

### `Upload.Adapters.S3`

To use the AWS adapter, you'll to install [ExAws](

Then, you'll need to following configuration:

config :upload, Upload, adapter: Upload.Adapters.S3
config :upload, Upload.Adapters.S3, bucket: "your_bucket_name"

### `Upload.Adapters.Test`

To use this adapter, you'll need to the following configuration:

config :upload, Upload, adapter: Upload.Adapters.Test

In your tests, you can make assertions:

setup do
  {:ok, _} = start_supervised(Upload.Adapters.Test)

test "files are uploaded" do
  assert {:ok, upload} = Upload.cast_path("/path/to/file.txt")
  assert {:ok, upload} = Upload.transfer(upload)
  assert length(Upload.Adapters.Test.get_uploads()) == 1

### `Upload.Adapters.Fake`

This adapter does pretty much nothing. It makes absolutely no attempt to persist uploads. This can be useful in unit tests where you want to completely bypass uploading.

To use this adapter, you'll need the following configuration:

config :upload, Upload, adapter: Upload.Adapters.Fake