{"metadata":{"image":[],"title":"","description":""},"api":{"url":"","auth":"required","params":[],"results":{"codes":[]},"settings":""},"next":{"description":"","pages":[]},"title":"File Uploads","type":"basic","slug":"file-uploads","excerpt":"","body":"One common task for web applications is uploading files. These files might be images, videos, PDFs, or files of any other type. In order to upload files through an HTML interface, we need a `file` input tag in a multipart form.\n\nPlug provides a `Plug.Upload` struct to hold the data from the `file` input. A `Plug.Upload` struct will automatically appear in our request parameters if a user has selected a file when they submit the form.\n\nLet's take this one piece at a time.\n\nIn the [`Ecto Models Guide`](http://www.phoenixframework.org/docs/ecto-models), we generated an HTML resource for users. We can reuse the form we generated there in order to demonstrate how file uploads work in Phoenix. Please see that guide for instructions on generating the users resource we'll be using here.\n\nThe first thing we need to do is change our form into a multipart form. The `form_for/4` function accepts a keyword list of options where we can specify this.\n\nHere is the form from `web/templates/user/form.html.eex` with that change in place.\n\n```elixir\n<%= form_for :::at:::changeset, @action, [multipart: true], fn f -> %>\n. . .\n```\n\nOnce we have a multipart form, we need a `file` input. Here's how we would do that, also in `form.html.eex`.\n\n```html\n. . .\n  <div class=\"form-group\">\n    <label>Photo</label>\n    <%= file_input f, :photo, class: \"form-control\" %>\n  </div>\n\n  <div class=\"form-group\">\n    <%= submit \"Submit\", class: \"btn btn-primary\" %>\n  </div>\n<% end %>\n```\n\nWhen rendered, here's what the HTML for that input looks like.\n\n```html\n<div class=\"form-group\">\n  <label>Photo</label>\n  <input class=\"form-control\" id=\"user_photo\" name=\"user[photo]\" type=\"file\">\n</div>\n```\n\nNote the `name` attribute of our `file` input. This will create the `\"photo\"` key in the `user_params` map which will be available in our controller action.\n\nThat's it from the form side. Now when users submit the form, a `POST` request will route to our `HelloPhoenix.UserController` `create/2` action.\n\n> Note: This photo input does not need to be part of our model for it to come across in the `user_params`. If we want to persist any properties of the photo in a database, however, we would need to add it to our `HelloPhoenix.User` model's schema.\n\nBefore we begin, let's add `IO.inspect user_params` to the top of our `HelloPhoenix.create/2` action in `web/controllers/user_controller.ex`. This will show the `user_params` in our development log so we can better see what's happening.\n\n```elixir\n. . .\n  def create(conn, %{\"user\" => user_params}) do\n    IO.inspect user_params\n. . .\n```\n\nSince we generated an HTML resource, we can now start our server with `mix phoenix.server`, visit [http://localhost:4000/users/new](http://localhost:4000/users/new), and create a new user with a photo.\n\nWhen we do that, this is what our `user_params` look like in the log.\n\n```elixir\n%{\"bio\" => \"Guitarist\", \"email\" => \"[email protected]\", \"name\" => \"Dweezil Zappa\", \"number_of_pets\" => \"3\",\n\"photo\" => %Plug.Upload{content_type: \"image/jpg\", filename: \"cute-kitty.jpg\", path: \"/var/folders/_6/xbsnn7tx6g9dblyx149nrvbw0000gn/T//plug-1434/multipart-558399-917557-1\"}}\n```\n\nWe have a \"photo\" key which maps to the pre-populated `Plug.Upload` struct representing our uploaded photo.\n\nTo make this easier to read, let's just focus on the struct itself.\n\n```elixir\n%Plug.Upload{content_type: \"image/jpg\", filename: \"cute-kitty.jpg\", path: \"/var/folders/_6/xbsnn7tx6g9dblyx149nrvbw0000gn/T//plug-1434/multipart-558399-917557-1\"}\n```\n\n`Plug.Upload` provides the file's content type, original filename, and path to the temporary file which Plug created for us. In our case, `\"/var/folders/_6/xbsnn7tx6g9dblyx149nrvbw0000gn/T//plug-1434/\"` is the directory which Plug created to put uploaded files in. It will persist across requests. `\"multipart-558399-917557-1\"` is the name Plug gave to our uploaded file. If we had multiple `file` inputs and if the user selected photos for all of them, we would have multiple files in this directory. Plug will make sure all the filenames are unique.\n\n> Note: This file is temporary, and Plug will remove it from the directory as the request completes. If we need to do anything with this file, we need to do it before then.\n\nOnce we have the `Plug.Upload` struct available in our controller, we can perform any operation on in we want. We can check to make sure the file exists with `File.exists?/1`, copy it somewhere else on the filesystem with `File.cp/2`, send it to S3 with an external library, or even email it with [Plug.Conn.send_file/5](http://hexdocs.pm/plug/Plug.Conn.html#send_file/5).\n\nThere's one last thing to note about file uploads. Let's create another user, this time without selecting a photo.\n\nWith no data from the `file` input, we get neither the \"photo\" key nor a `Plug.Upload` struct. Here are the `user_params` from the log.\n\n```elixir\n%{\"bio\" => \"Guitarist\", \"email\" => \"[email protected]\", \"name\" => \"Dweezil Zappa\", \"number_of_pets\" => \"3\"}\n```","updates":[],"order":4,"isReference":false,"hidden":false,"sync_unique":"","link_url":"","link_external":false,"_id":"559218ad1da5250d001e967c","category":{"sync":{"isSync":false,"url":""},"pages":["559218ad1da5250d001e9675","559218ad1da5250d001e9676","559218ad1da5250d001e9677","559218ad1da5250d001e9678","559218ad1da5250d001e9679","559218ad1da5250d001e967a","559218ad1da5250d001e967b","559218ad1da5250d001e967c","559218ad1da5250d001e967d","55921ed65068e60d002ba044"],"title":"Bonus Guides","slug":"bonus-guides","order":4,"from_sync":false,"reference":false,"_id":"559218ad1da5250d001e9672","version":"559218ac1da5250d001e966f","__v":2,"createdAt":"2014-12-03T21:36:49.014Z","project":"54348ec95b10711400c6c445"},"user":"5435b410495d5d0800f3a603","project":"54348ec95b10711400c6c445","version":{"version":"0.14.0","version_clean":"0.14.0","codename":"","is_stable":false,"is_beta":true,"is_hidden":false,"is_deprecated":false,"categories":["559218ad1da5250d001e9670","559218ad1da5250d001e9671","559218ad1da5250d001e9672","559218ad1da5250d001e9673","559218ad1da5250d001e9674"],"_id":"559218ac1da5250d001e966f","releaseDate":"2015-06-30T04:18:52.132Z","__v":1,"createdAt":"2015-06-30T04:18:52.132Z","forked_from":"5558c642eb56ae2f00f714fc","project":"54348ec95b10711400c6c445"},"createdAt":"2015-06-18T21:42:27.913Z","githubsync":"","__v":1}
One common task for web applications is uploading files. These files might be images, videos, PDFs, or files of any other type. In order to upload files through an HTML interface, we need a `file` input tag in a multipart form. Plug provides a `Plug.Upload` struct to hold the data from the `file` input. A `Plug.Upload` struct will automatically appear in our request parameters if a user has selected a file when they submit the form. Let's take this one piece at a time. In the [`Ecto Models Guide`](http://www.phoenixframework.org/docs/ecto-models), we generated an HTML resource for users. We can reuse the form we generated there in order to demonstrate how file uploads work in Phoenix. Please see that guide for instructions on generating the users resource we'll be using here. The first thing we need to do is change our form into a multipart form. The `form_for/4` function accepts a keyword list of options where we can specify this. Here is the form from `web/templates/user/form.html.eex` with that change in place. ```elixir <%= form_for @changeset, @action, [multipart: true], fn f -> %> . . . ``` Once we have a multipart form, we need a `file` input. Here's how we would do that, also in `form.html.eex`. ```html . . . <div class="form-group"> <label>Photo</label> <%= file_input f, :photo, class: "form-control" %> </div> <div class="form-group"> <%= submit "Submit", class: "btn btn-primary" %> </div> <% end %> ``` When rendered, here's what the HTML for that input looks like. ```html <div class="form-group"> <label>Photo</label> <input class="form-control" id="user_photo" name="user[photo]" type="file"> </div> ``` Note the `name` attribute of our `file` input. This will create the `"photo"` key in the `user_params` map which will be available in our controller action. That's it from the form side. Now when users submit the form, a `POST` request will route to our `HelloPhoenix.UserController` `create/2` action. > Note: This photo input does not need to be part of our model for it to come across in the `user_params`. If we want to persist any properties of the photo in a database, however, we would need to add it to our `HelloPhoenix.User` model's schema. Before we begin, let's add `IO.inspect user_params` to the top of our `HelloPhoenix.create/2` action in `web/controllers/user_controller.ex`. This will show the `user_params` in our development log so we can better see what's happening. ```elixir . . . def create(conn, %{"user" => user_params}) do IO.inspect user_params . . . ``` Since we generated an HTML resource, we can now start our server with `mix phoenix.server`, visit [http://localhost:4000/users/new](http://localhost:4000/users/new), and create a new user with a photo. When we do that, this is what our `user_params` look like in the log. ```elixir %{"bio" => "Guitarist", "email" => "[email protected]", "name" => "Dweezil Zappa", "number_of_pets" => "3", "photo" => %Plug.Upload{content_type: "image/jpg", filename: "cute-kitty.jpg", path: "/var/folders/_6/xbsnn7tx6g9dblyx149nrvbw0000gn/T//plug-1434/multipart-558399-917557-1"}} ``` We have a "photo" key which maps to the pre-populated `Plug.Upload` struct representing our uploaded photo. To make this easier to read, let's just focus on the struct itself. ```elixir %Plug.Upload{content_type: "image/jpg", filename: "cute-kitty.jpg", path: "/var/folders/_6/xbsnn7tx6g9dblyx149nrvbw0000gn/T//plug-1434/multipart-558399-917557-1"} ``` `Plug.Upload` provides the file's content type, original filename, and path to the temporary file which Plug created for us. In our case, `"/var/folders/_6/xbsnn7tx6g9dblyx149nrvbw0000gn/T//plug-1434/"` is the directory which Plug created to put uploaded files in. It will persist across requests. `"multipart-558399-917557-1"` is the name Plug gave to our uploaded file. If we had multiple `file` inputs and if the user selected photos for all of them, we would have multiple files in this directory. Plug will make sure all the filenames are unique. > Note: This file is temporary, and Plug will remove it from the directory as the request completes. If we need to do anything with this file, we need to do it before then. Once we have the `Plug.Upload` struct available in our controller, we can perform any operation on in we want. We can check to make sure the file exists with `File.exists?/1`, copy it somewhere else on the filesystem with `File.cp/2`, send it to S3 with an external library, or even email it with [Plug.Conn.send_file/5](http://hexdocs.pm/plug/Plug.Conn.html#send_file/5). There's one last thing to note about file uploads. Let's create another user, this time without selecting a photo. With no data from the `file` input, we get neither the "photo" key nor a `Plug.Upload` struct. Here are the `user_params` from the log. ```elixir %{"bio" => "Guitarist", "email" => "[email protected]", "name" => "Dweezil Zappa", "number_of_pets" => "3"} ```