How to load different templates and views if a user is logged in

Hi, I’m new to Elixir and Phoenix so far the support/community and language has been great. I’m still reading the docs and starting to understand everything but one thing I can’t find is the correct way to do conditional template/views loading.

In my app I’m using two different HTML themes ones for the public static website and one for the user admin or dashboard, when I user is logged in I would like to use the specific theme so I need to load a different app.html.eex how can this be done?

You might add a plug somewhere in your pipeline (router or endpoin.ex) which would assign a template or a whole view based on the user data.

It would be something like this

In the router (or endpoint):

def MyApp.Router do
  use Phoenix.Router

  pipeline :browser do # or any other pipeline
    # ...
    # the options [admin: ..., user: ...] I just picked as an example
    plug(MyApp.Plugs.Theme, [admin: "admin.html.eex", user: "app.html.eex"])
    # ...
  end
end

Then you can create a new folder under your /lib to put your custom plugs in (like /lib/plugs) and create a theme.ex plug there:

defmodule MyApp.Plugs.Theme do
  @moduledoc "Assings a theme to the connection based on current user."

  import Phoenix.Controller, only: [put_layout: 2]

  # just an example how to init options in plug
  def init(opts) do
    admin_theme = opts[:admin] 
    user_theme = opts[:user]
    {admin_theme, user_theme}
  end

  def call(%Plug.Conn{assigns: assigns} = conn, {admin_theme, user_theme}) do
    # :admin? would be replaced with your own assign that defines whether the 
    # current user is an admin
    # maybe you can use https://hexdocs.pm/coherence/Coherence.html#current_user/1 instead
    if assigns[:admin?] do 
      put_layout(conn, admin_theme)
    else
      put_layout(conn, user_theme)
    end
  end
end
1 Like

Eh depends on how complex you need it, I usually just pepper some things like this around:

<%= if Auth.get_verified_account_id(@conn, nil) == nil do %>
Logged out.
<% else %>
Logged in
<% end %>

Which of course you could bring in ‘other’ templates via render too.

I guess the easiest way I can think of is doing it in my home controller which has the following how would I do it here

defmodule MagnifyWeb.HomeController do
  use MagnifyWeb, :controller

  def index(conn, _params) do
    render conn, "index.html"
  end
end

using https://hexdocs.pm/coherence/Coherence.html#current_user/1

logged_in?(conn)

I think you might as well try to utilize the put_layout/2 function to specify the layout you wish to use in a certain function in your controller i.e

def index(conn, _params) do
  conn
  |> put_layout("admin.html")
  |> render("index.html")
end

or set a default layout in the controller by defining the layout plug i.e plug :put_layout, "mylayout.html"

what about loading a template partial based on user roles. Would a good place to place that logic be in the route’s controller module?

Sure, though I’m usually a bit lazy and just put a case in my template directly to dispatch to the correct render. ^.^;