3
votes

I am trying to create a new route that will allow users to download the files they have uploaded. I created this route under the "/" scope.

get "/media/:filepath", MediaFilesController, :download

For now, I'm just trying to send images that are located in a folder uploads that is located at the root of the project. In short, if someone tries to access /media/file.png, it will send the file located at <project_folder>/uploads/file.png. Here's the code for it:

defmodule App.MediaFilesController do
  use App.Web, :controller
  import Plug.Conn

  @media_folder "/uploads"

  def download(conn, %{"filepath" => filepath}) do
    path = "#{System.cwd}/#{@media_folder}/#{filepath}"
    {:ok, file} = File.open(path)
    conn
    |> put_resp_content_type("image/png")
    |> send_file(200, file)
  end
end

When I try to load the URL /media/file.png, I'm getting this error:

[error] #PID<0.579.0> running App.Endpoint terminated Server: localhost:4000 (http) Request: GET /media/file.png
** (exit) an exception was raised:
    ** (FunctionClauseError) no function clause matching in Plug.Conn.send_file/5

I do not understand why I'm getting this error. The documentation precisely says:

send it back to the client with Plug.Conn.send_file/5.

Why am I getting this error?

1

1 Answers

2
votes

send_file/5 expects a path, not a file.

So in the end, the function looks like this:

def download(conn, %{"filepath" => filepath}) do     
  path = "#{System.cwd}/#{@media_folder}/#{filepath}"
  conn                                               
  |> put_resp_content_type("image/png")              
  |> send_file(200, path)                            
end