Bow.Uploader behaviour (Bow v0.4.1) View Source

Base module for definig uploaders

Definition

Minimal usage example:

defmodule MyUploader do
  use Bow.Uploader

  # specify storage directory
  def store_dir(_file) do
    "uploads"
  end
end

Full example

defmodule AttachmentUploader do
  use Bow.Uploader

  # define what versions to generate for given file
  def versions(_file) do
    [:original, :thumb]
  end


  # keep the origianal file name
  def filename(file, :original), do: file.name

  # prepend "thumb_" for thumbnail
  def filename(file, :thumb),    do: "thumb_#{file.name}"


  # do nothing with original file
  def transform(file, :original), do: transform_original(file)

  # generate image thumbnail
  def transform(source, target, :thumb) do
    Bow.Exec.exec source, target,
      "convert ${input} -strip -gravity Center -resize 250x175^ -extent 250x175 ${output}"
  end


  # specify storage directory
  def store_dir(file) do
    "attachments/#{file.scope.id}"
  end

  # specify storage options
  def store_options(_file) do
    [acl: :public_read]
  end
end

Direct usage

file = MyUploader.new(path: "path/to/file")
Bow.store(file)

# you can pass any options that are valid for `Bow.new/1`
file = MyUploader.new(name: "avatar.png", scope: %{id: 1})

Integration with Ecto

See Bow.Ecto for usage with Ecto.Schema

Link to this section Summary

Callbacks

Defines custom assets host.

Customize filenames for given version.

Defines storage dir for given file.

Defines store custom options.

Define transformation to given version.

Validate incoming file before processing.

Return list of versions to be generated for given file.

Link to this section Callbacks

Specs

assets_host() :: binary()

Defines custom assets host.

Default implementation returns empty value (nil)

Example usage with Bow.Storage.S3

defmodule MyUploader do
  # ...
  def assets_host() do
    "https://assets.example.com/"
  end
end

Specs

filename(file :: Bow.t(), version :: atom()) :: String.t()

Customize filenames for given version.

The default implementation uses original filename for :original version and others are prefixed with "#{version}_"

IMPORTANT: This function is used both when uploading files and when generating URLs so it must be stable.

Example

defmodule MyImageUploader do
  # keep the origianal file name
  def filename(file, :original),  do: file.name

  # for :pdf version prefix with _pdf and add .pdf extension
  def filename(file, :pdf),       do: "pdf_#{file.rootname}.pdf"

  # for any other version prefix with version name
  def filename(file, version),     do: "#{version}_#{file.name}"
end

Specs

store_dir(file :: Bow.t()) :: String.t()

Defines storage dir for given file.

There is no default implementation - it must be provided by uploader

Simple usage

defmodule MyUploader do
  # ...
  def store_dir(_file) do
    "uploads"
  end
end

Usage with scope (usually when using Bow.Ecto)

defmodule MyUploader do
  # ...
  def store_dir(file) do
    "attachments/#{file.scope.id}"
  end
end

Specs

store_options(file :: Bow.t()) :: keyword()

Defines store custom options.

Default implementation returns empty map (%{})

Example usage with Bow.Storage.S3

defmodule MyUploader do
  # ...
  def store_options(_file) do
    [acl: :public_read]
  end
end
Link to this callback

transform(source, target, version)

View Source

Specs

transform(source :: Bow.t(), target :: Bow.t(), version :: atom()) ::
  {:ok, target :: Bow.t()}
  | {:ok, target :: Bow.t(), next_versions :: [atom()]}
  | {:error, reason :: any()}

Define transformation to given version.

The return value can be either:

  • {:ok, transformed_file} - when transformation is successful
  • {:ok, transformed_file. next_versions} - when transformation is successful and other versions should be generated based on this one (instead of the original file)
  • {:error, reason} - in case transformation failure

Example

defmodule MyImageUploader do
  # generate image thumbnail
  def transform(source, target, :thumb) do
    # Bow.Exec allows executing any system command replacing ${input} and ${output}
    # with correct paths. It can also take :timeout option to prevent resource consumtion.
    # Refer to Bow.Exec documentation for more details
    Bow.Exec.exec source, target,
      "convert ${input} -strip -gravity Center -resize 250x175^ -extent 250x175 ${output}"
  end
end

Derived versions generation

defmodule MyImageUploader do
  # generate image thumbnail and then micro_thumb version based on that
  def transform(source, target, :thumb) do
    with {:ok, thumb_file} <- Bow.Exec.exec source, target
      "convert ${input} -strip -gravity Center -resize 250x175^ -extent 250x175 ${output}" do
      {:ok, thumb_file, [:micro_thumb]}
    end
  end
end

Specs

validate(file :: Bow.t()) :: :ok | {:error, reason :: any()}

Validate incoming file before processing.

Mostly useful in conjunction with validate_changeset/2 from Bow.Ecto module. The default implementation simply returns :ok

Example

defmodule MyImageUploader do
  def validate(%{ext: ext}) when ext in ~w(.jpg .png), do: :ok
  def validate(_), do: {:error, :extension_not_allowed}
end

Specs

versions(file :: Bow.t()) :: [atom()]

Return list of versions to be generated for given file.

The default returns a list with single element - [:original]

Simple definition:

defmodule MyImageUploader do
  # ...
  def versions(_file) do
    [:original, :thumb]
  end
end

Custom logic based on input file:

defmodule MyDocumentUploader do
  # ...
  def versions(file) do
    case file.ext do
      ".pdf" -> [:original]
      ".doc" -> [:original, :pdf] # generate :pdf version for .doc files
    end
  end
end

Link to this section Functions

Link to this function

transform_original(source, target)

View Source