Reputation: 701
How can I define my Plug/Phoenix routes so that I have a single set of URLs, but show different content depending on what kind of user is logged in?
Eg, a user should visit /home
and see a list of posts, an admin should visit /home
and see a list of users, or children see a list of activities and parents see a list of test scores.
The pages should have wildly different content and behaviours, different root layouts, functionality and features, etc.
Do I have to dispatch to one "global" HomeController(Live)
and mix it all in together?
Upvotes: -1
Views: 72
Reputation: 2902
Use the phx.gen.auth as a example.
It uses two gates (one at the plug, the other via LiveSession) to define a @current_user
assigns. From that point you can gate if a user should have access to a given route. Once a given route has rendered then its a matter of conditions in the Liveview and in the heex. You can gate assignment of values in the Liveview by introspecting the @current_user but also use :if={@some_value}
to also gate if a given thing should be rendered in the heex/layout
For example in my layout for my site navigation I have a nav component that takes a current_user={@current_user}
then in that component I use that assigns like so.
<.link :if={@current_user && @current_user.admin} href={~p"/admin"}>
Admin
</.link>
And I just make sure to pass in my @current_user to that layout component.
That link could just as well be a liveview component or a div showing or omitting based on any value I pre assigned in my liveview.
Upvotes: -1
Reputation: 501
Since you can't forward controller actions using plugs
from your router
, the cleanest option would be having 3 routes, eg: /home
, /admin/home
and /user/home
then handling the redirect. You can also reduce to 2 routes and handle the redirect from the user one.
Eg: /home
forwards to HomeController#index
When user is marked as an admin, controller redirects to /admin/home
, otherwise renders user home's template.
Redirects could also be done better using a Plug
Otherwise, if you still want to keep only one route, you'll want to make your checks directly in the HomeController#index
then render the correct layout and template.
Eg:
defmodule MyAppWeb.HomeController do
def index(conn, _params), do: render_index(conn)
defp render_index(%{assigns: %{admin: true}}) do
conn
|> put_layout(html: {MyApp.Layouts, :admin_layout})
|> render(:admin_index)
end
defp render_index(%{assigns: %{admin: false}}) do
conn
|> put_layout(html: {MyApp.Layouts, :user_layout})
|> render(:user_index)
end
end
Upvotes: 0