Tessy Thomas
Tessy Thomas

Reputation: 1485

File Upload to Local using Acr in Elixir

I am using Arc.Definition(https://github.com/stavro/arc) for uploading an image to the Local Storage.

My file_service.ex is below:

defmodule MyApp.FileService do
  use Arc.Definition
  use Arc.Ecto.Definition

  @image_types ~w(.jpg .jpeg .png .gif)
  @versions [:original]
  @default_filename "image.png"

  @heights %{
    medium: 400
  }

  @widths %{
    medium: 400
  }

  def __storage, do: Arc.Storage.Local

  def upload_image(%Plug.Upload{} = image, resource_type, resource_id) do
    store({%Plug.Upload{path: image.path, filename: @default_filename},
      %{resource_type: resource_type, resource_id: resource_id}})
  end

  def upload_base64_image(base64_image, resource_type, resource_id) do
    store({%{filename: @default_filename, binary: base64_image_to_binary(base64_image)}})
  end 

  def delete_file(image_url, resource) do
    delete({image_url, resource})
  end

  defp base64_image_to_binary("data:image/" <> rest) do
    rest
    |> String.replace("\n", "")
    |> String.split(",")
    |> Enum.at(1)
    |> Base.decode64!
  end
  defp base64_image_to_binary(base64_image) do
    base64_image
    |> String.replace("\n", "")
    |> Base.decode64!
  end
end

But, I am getting an error saying "no function clause matching in Arc.Actions.Store.store".

The stack trace is below:

** (FunctionClauseError) no function clause matching in Arc.Actions.Store.store/2 (arc) lib/arc/actions/store.ex:8: Arc.Actions.Store.store(MyApp.FileService, {%{binary: <<255, 216, 255, 225, 3, 48, 69, 120, 105, 102, 0, 0, 73, 73, 42, 0, 8, 0, 0, 0, 58, 0, 50, 1, 2, 0, 20, 0, 0, 0, 198, 2, 0, 0, 15, 1, 2, 0, 10, 0, 0, 0, 218, 2, 0, 0, 1, 1, ...>>, filename: "image.png"}})

Anyone, please help?

Upvotes: 2

Views: 607

Answers (1)

chris
chris

Reputation: 2863

Your code

 def upload_base64_image(base64_image, resource_type, resource_id) do
    store({%{filename: @default_filename, binary: base64_image_to_binary(base64_image)}})
  end 

's store is using wrong.

It only accept tuple(file, scope) or filepath(map).

So it should be: store(%{filename: @default_filename, binary: base64_image_to_binary(base64_image)}).

See github's example:

# Store a file from a connection body
{:ok, data, _conn} = Plug.Conn.read_body(conn)
Avatar.store(%{filename: "file.png", binary: data})

I figure it out by reading traceback and arc's store implementaion:

  def store(definition, {file, scope}) when is_binary(file) or is_map(file) do
    put(definition, {Arc.File.new(file), scope})
  end

  def store(definition, filepath) when is_binary(filepath) or is_map(filepath) do
    store(definition, {filepath, nil})
  end

Upvotes: 2

Related Questions