stavro / arc_ecto

An integration with Arc and Ecto.
255 stars 149 forks source link

Store original file size and filename to Model #80

Open prihandi opened 7 years ago

prihandi commented 7 years ago

Is there any way to store original filename and file size on Repo Model ? I want to calculate total uploaded file size per user, if it provided directly from database it would be very helpful. Thanks Dwi

kiere commented 5 years ago

@prihandi I am doing this with the File.stat function. In my changeset I have something like this (kind of hacky for now):

(my %Plug.Upload{} is in the key "attachment")

  def create_changeset(relationship_attachment, attrs) do
    upload = Map.get(attrs, "attachment")

    relationship_attachment
    |> changeset(attrs)
    |> put_file_size(upload) # or we could just send this from the JavaScript File API?
    |> validate_required([:file_size])
    |> put_mime_type(upload)
    |> validate_required([:mime_type])
    |> cast_attachments(attrs, [:attachment])
    |> validate_required([:attachment])
  end

  defp put_mime_type(changeset, %Plug.Upload{} = upload) do
    put_change(changeset, :mime_type, upload.content_type)
  end
  defp put_mime_type(changeset, _), do: changeset

  defp put_file_size(changeset, %Plug.Upload{} = upload) do
    put_change(changeset, :file_size, file_size(upload))
  end
  defp put_file_size(changeset, _), do: changeset

  defp file_size(%Plug.Upload{} = upload) do
    case File.stat(upload.path) do
      {:ok, stats} ->
        stats.size
      {:error, _} ->
        nil
    end
  end

This is the first project I'm actually doing this on, so all this is still a work in progress and I'm sure this will change quickly. But it works for now.

I moved off the use of the JavaScript File API because I realized I would want this consistently done on the server and not relying on potentially varying implementations in different browsers AND if we implemented an API for a native app or something else, I would be relying on one more out-of-app variation of file size calculation. This way it's done the same regardless of the client.