Hey folks, there’s something basic I’m missing about Phoenix controllers. I have an action, DocumentController.new
, running at /documents/new:
def new(conn, _params) do
user = conn.assigns[:current_user]
changeset =
Documents.change_document(%Document{
settings: Documents.change_settings(%Settings{}, %{}, user)
})
render(conn, "new.html", changeset: changeset)
end
My form creation line in the template reads:
<%= form_for @changeset, Routes.document_path(@conn, :create), [id: "form", multipart: true], fn f -> %>
One thing I notice, though, is that if /documents/new doesn’t validate or succeed in creation, the URL is then set to /documents, even though the new document form is rendered. Further, I get a _method="put"
or similar in my <form>
tag. So if my first form submission errors, future form submissions swap out the method, meaning they don’t route to the create
action because they try a PUT rather than a POST.
First, should I care that I’m not returning to /documents/new? I’d expect to appear back on /documents/new with the form in its errored state, but I don’t see how to pass existing form state back into the new action.
Next, how do I fix this? In my system, documents can’t be updated. They either create or don’t, then subordinate records are created/updated separately. I think there’s an action
parameter that has some effect on this, and I see it in the generated scaffolds, but since I don’t want an update operation, I removed it to simplify the generated code. Should I be adding it as a hidden field in new.html.eex, merging the parameters in somehow, etc.?
Here’s my create
action as well. It’s a bit convoluted because documents can be created either via URL or an uploaded file, and I don’t know how to indicate that one or the other is required:
def create(conn, %{"document" => document_params}) do
user = conn.assigns[:current_user]
document_params =
if String.trim(document_params["url"]) != "" do
Map.put(document_params, "file", document_params["url"])
else
document_params
end
case Documents.create_document(document_params, user) do
{:ok, document} ->
conn
|> redirect(to: Routes.document_path(conn, :show, document, "html"))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
Thanks.