markson edwardson
markson edwardson

Reputation: 701

How to serve a different controller/liveviews from one route for different users roles

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

Answers (2)

MorphicPro
MorphicPro

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

icra
icra

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

Related Questions