phoenix

Using `form_for` in Phoenix without `Ecto.Changeset`

form_for expect the first argument to be any data structure that implements the Phoenix.HTML.FormData protocol. Phoenix implements this protocol for Plug.Conn. Hence to create form not backing by any data layer:

<%= form_for @conn, to: Routes.search_path(@conn, :new) do |f| %>
  ...
<% end %>

Adding CSS class to Phoenix `form_for`

Passing in class: "form-class" to form_for in Phoenix doesn’t work. Instead, it expect a keyword list. Hence, to add custom CSS class to form_for, use:

<%= form_for @conn, ... , [class: "form-class"], fn f -> %>
   ...
<% end %>

All of the HTML attributes of a form element can be pass in this way. For more available options, see Phoenix.HTML.Form documentation.

Send temporary file in Phoenix controller

TLDR: Use Phoenix.Controller.send_download/3 to send binary as download.


There will be some occasions when you need to send a file to user in your applications. In Phoenix, there are a couple ways of doing it. The most straightforward one is to programmatically create a file and send it to user using Plug.Conn.send_file/5.

For example:

def export(conn, _params) do
  # Create file
  filename = "test.md"
  File.write(filename, "Hello World")
  
  # Send file
  conn
  |> put_resp_header("content-disposition", ~s(attachment; filename="#{filename}"))
  |> send_file(200, filename)
end

However, this approach create a file locally in your production server and require some clean up after that. (I don’t really know how to delete a file only after the request succeed)

Luckily, there is another approach, which is using Phoenix.Controller.send_download/3. This function allow us to send binary directly as a download. Hence, file creation is not needed.

For example:

def export(conn, _params) do
  filename = "test.md"
  
  # Send file
  conn
  |> send_download({:binary, "Hello World"}, filename: filename)
end

For more, refer to the send_file/5 and send_download/3 documentation.

Tags: phoenix