4

Hi I'm using different domain names to load different data sets. I'm currently using a custom plug to load the correct domain id based on the hostname. E.g. got this in my endpoint.ex just before the router:

plug WebApp.DomainCheck
socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
...
plug WebApp.Router

And

defmodule WebApp.DomainCheck do
  import Plug.Conn
  @behaviour Plug

  def init([]), do: []

  def call(conn, _options \\ []) do
    domains = Model.load_allowed_domains()
    case Map.get(domains, conn.host) do
      nil ->
        conn
        |> resp(401, "Domain not allowed")
        |> halt()

      domain_id ->
        conn
        |> assign(:domain_id, domain_id)
    end
  end
end

Now this works for normal View as I have the domain_id assign in each of them. But how do I get the domain data injected into my LiveViews as well from a plug?

Currently I've code duplicated the same domain check into every LiveViews mount() page:

defmodule WebApp.WelcomeLive do
  use WebApp, :live_view

  @impl true
  def mount(_args, _session, socket) do
    domains = Model.load_allowed_domains()
    host = socket.host_uri.host
    case Map.get(domains, host) do
      nil -> {:error, "Domain not allowed"}
      domain_id -> {:ok, assign(socket, :domain_id, domain_id)}
    end
  end

Is there any way I can make a plug effective in pushing this data down to the live views without need to add code to each mount?

Dominic
  • 786
  • 6
  • 8

1 Answers1

6

I had a similar use case in my app where my plug puts the a user struct on the assigns and I wanted to keep that data inside live view without reloading all stuff.

The only way I could achieve that was using the option session from the live route passing it a MFA.

In the router you will have something like

live "/page", WebApp.SomeLiveView, :show, session: {WebAppp.Helpers, :keep_domain_id, []}

and your WebApp.Helpers will have that function returning what you want to be passed to your live view as session.

defmodule WebApp.Helpers do
  def keep_domain_id(conn) do
    %{"domain_id" => conn.assigns.domain_id}
  end
end

Then in your mount on you will have "domain_id" key in your session

defmodule WebApp.WelcomeLive do
  use WebApp, :live_view

  @impl true
  def mount(_args, %{"domain_id" => domain} = _session, socket) do
    ...
  end
end
Evaldo Bratti
  • 7,078
  • 2
  • 18
  • 19
  • Thanks for that! I think this works great for a user object, but isn't this session shared between all views? E.g. if a user has two open tabs on different host urls wouldn't the session values override each other? – Dominic Dec 21 '20 at 07:10
  • Though they share the standard session from the client, some values will be the same indeed, but as you are getting `domain_id` value from the connection (in this case, from each tab), it will put the correct value in the session to that specific live view. – Evaldo Bratti Dec 21 '20 at 11:25
  • 1
    I'll try that and mark as the right answer if it works. – Dominic Dec 22 '20 at 13:02
  • Unfortunately the `session` argument [was removed in LiveView 0.16.0 (2021-08-10)](https://github.com/phoenixframework/phoenix_live_view/blob/master/CHANGELOG.md#0160-2021-08-10). One should [define `on_mount` hook](https://github.com/phoenixframework/phoenix_live_view/blob/42632f5535c66a664c9dcfcc4530690011fbec8e/guides/server/security-model.md#mounting-considerations) and mount that to any relevant LiveView(s). – mlen108 Aug 13 '22 at 06:20