root
Setting dynamic layouts in LiveViews that correspond with the hostname
Hello everyone.
I have an app that’s going to be setting the layout dynamically according to the current domain name. I’m trying to figure out a way to do it in LiveView.
I’ve gotten to the point where I have an on_mount helper that gets the current hostname and makes it available in assigns, but I’m not able to use that from within the LiveView mount calls, because the helper depends on hooking handle_params. The only other place to set the layout (as far as I know) is in the router or in the myapp_web file where the :live_view helpers are defined, and I’m not seeing how to get access to the hostname from either of those locations.
Is there a recommended way to do this that I’ve missed?
Marked As Solved
root
Okay…
router.ex
...
# put host and configuration data into session for retrieval from liveview
defp sessionify_configuration(conn, _opts) do
import Plug.Conn
case MyApp.Sites.Domain.get_by_name(conn.host) do
{:ok, domain} ->
configuration =
domain.site_id
|> MyApp.Sites.Site.get_by_id!()
|> MyApp.Sites.load!(:configuration)
|> Map.get(:configuration)
conn
|> put_session(:configuration, configuration)
|> put_session(:current_host, conn.host)
|> put_session(:current_path, conn.request_path)
{:error, error} ->
IO.inspect(error)
raise "No Domain found with the name " <> conn.host
conn
end
end
pipeline :do_config do
plug :sessionify_configuration
end
scope "/", MyAppWeb do
pipe_through [:browser, :do_config]
# login not required
ash_authentication_live_session :authenticated_optional,
on_mount: [
{MyAppWeb.LiveUserAuth, :live_user_optional},
{MyAppWeb.AssignConfiguration, :assign_configuration}
] do
live "/", PublicLive.Index, :index
end
...
assign_configuration.ex
def on_mount(:assign_configuration, _params, session, socket) do
socket =
socket
|> Phoenix.Component.assign(:configuration, Map.get(session, "configuration"))
|> Phoenix.Component.assign(:current_host, Map.get(session, "current_host"))
|> Phoenix.Component.assign(:current_path, Map.get(session, "current_path"))
{:cont, socket}
end
index.ex
def mount(_params, _session, socket) do
socket =
socket
|> assign(:page_title, "public")
|> assign(:testificate, "testificatey")
layout = {MyAppWeb.Layouts, socket.assigns.configuration.theme}
{:ok, socket, layout: layout}
end
This is the flow I have right now that’s working! I was able to remove extraneous hooks and consolidate some functionality into the on_mount. And it looks like Phoenix actually is letting me pass the layout template as a string, too, although it does complain that this is deprecated. So no String.to_atom for now (and if I do have to do that later I think I can just whitelist it based on existing themes).
So the only thing I have to append to every liveview is
layout = {MyAppWeb.Layouts, socket.assigns.configuration.theme}
{:ok, socket, layout: layout}
Not too bad.
And to be clear I meant like they could potentially manipulate the session based on the hostname. If you are whitelisting hostnames then it’s no problem.
This area is all public stuff you can view by simply going to that site, so that should be fine as I understand it. Unless there’s anything drastic I’m missing.
Also Liked
olivermt
sodapopcan
Wellllllll ****. Could you add it to the session from a plug so it’s available in mount? Maybe not ideal. I don’t think I can be much help here as I’ve never actually done this myself. I’m interested, though, so hopefully someone else can help!
(and yes, I also read that same thread and how I set the current URL too
)
EDIT: Ha, re: post that beat me to the punch
benwilson512
The session is signed by default, so it is not editable by the user. You can also encrypt it to make it impossible for the user to view.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









