I am currently in the “Writing an Authentication Plug” section of chapter 5 and I stumbled upon something that I did not fully understand (might be more Elixir related to a certain extent…). Anyway the controller level plug implementation given is the following:
defp authenticate(conn, _opts) do
if conn.assigns.current_user do
conn
else
conn
|> put_flash(:error, "You must be logged in to access that page")
|> redirect(to: page_path(conn, :index))
|> halt()
end
end
Now I thought to myself that if/else or cond can (should, depending on who you talk to…) be changed to leverage pattern matching. So I did a quick refactor as follow:
defp authenticate(%Plug.Conn{assigns: %{current_user: nil}} = conn, _opts) do
conn
|> put_flash(:error, "You must be logged in to access that page")
|> redirect(to: page_path(conn, :index))
|> halt()
end
defp authenticate(conn, _opts) do
conn
end
And that seems to be working but I thought it was a bit heavy on the eye with the nested pattern matching inside the function declaration so I thought I would refactor it again to use guard clause instead:
defp authenticate(conn, _opts) when is_nil(conn.assigns.current_user) do
conn
|> put_flash(:error, "You must be logged in to access that page")
|> redirect(to: page_path(conn, :index))
|> halt()
end
defp authenticate(conn, _opts) do
conn
end
Unfortunately, with this approach I keep receiving the following compilation error:
== Compilation error on file web/controllers/user_controller.ex ==
** (CompileError) web/controllers/user_controller.ex:34: cannot invoke remote function conn.assigns().current_user/0 inside guard
(stdlib) lists.erl:1354: :lists.mapfoldl/3
web/controllers/user_controller.ex:34: (module)
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
Now I did check the Plug.Conn implementation and it clearly states that assigns
is of type %{atom => any}
, so I guess I am missing something here.
Would anyone be willing to help me understand what is happening here?
Thanks,
Fred