Yes of course. I fooled myself thinking that maybe Phoenix could be doing some “magic” behind the scenes. But it makes total sense that the “conn” struct is different because it’s a different request.
I’m gonna study other options of what can be done, but I think this could be encapsulated in a helper? Something like a redirect_with/3
, to put the errors on the session and then retrieve on the other side (maybe a plug?).
Update: So, I’ve read a little bit about Plug and this is what I came up with (It’s probably a naive implementation, but right now I can get full Post Redirect Get):
defmodule MyAppWeb.Plug.TempData do
import Plug.Conn
use MyAppWeb, :controller
@session_key "temp_data"
@assigns_key :loaded
def init(opts), do: opts
def call(%Plug.Conn{private: %{:plug_session => %{@session_key => temp}}} = conn, _opts) do
conn
|> assign(@assigns_key, temp)
|> delete_session(@session_key)
end
def call(conn, _opts), do: conn
def load_redirected(conn, default) do
conn.assigns[@assigns_key] || default
end
def redirect_with(conn, object, opts) do
conn
|> fetch_session()
|> put_session(@session_key, object)
|> redirect(opts)
end
end
Then it can be used like:
import MyAppWeb.Plug.TempData, only: [redirect_with: 3, load_redirected: 2]
alias MyAppWeb.Plug.TempData
plug TempData
def new(conn, _params) do
changeset = load_redirected(conn, Context.change_resource(%Resource{}))
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"resource" => resource_params}) do
case Context.create_resource(resource_params) do
{:ok, resource} ->
conn
|> put_flash(:info, "Resource created successfully.")
|> redirect(to: Routes.resource_path(conn, :show, resource))
{:error, %Ecto.Changeset{} = changeset} ->
redirect_with(conn, changeset, to: Routes.resource_path(conn, :new))
end
end