Phoenix liveview multitenancy

I tried latest Phoenix with liveview. It’s great but I hit a wall. I’m not able to get to domain used by a request. Before it was possible to use conn.host to get current host. I used this value to determine users domain. But socket does not contain this information. Since I need to deal with anonymous users sessions are not very helpful.

Basically I get the domain get domain object from DB. I get the domain primary key and use it to filter data based on domain. In case of new objects I put domain PK in FK so I will show only domain data based on visited domain. This works great unless liveview is involved.

I tired to look it up in docs but there was nothing useful. I tried to look even in the source code of liveview. Still nothing. But I’ve started with Phoenix 3 weeks ago so please don’t hammer me with RTFM.

2 Likes

Welcome!

I have a very similar scenario, here’s what I do. At the live view connect:

const liveSocket = new LiveSocket("/live", Socket, {
  hooks: Hooks,
  params: {
    _csrf_token: csrf_token,
    host: window.location.hostname
  }
});

Then, you can call get_connect_params(socket) to get the "host" param.

9 Likes

connect params is a great option to pass up client state, but you can also get the full url in handle_params. It will be the second argument :slight_smile:


def handle_params(_params, url, socket) do
  host = URI.parse(url).host
  # ... profit
end
8 Likes

Thanks, the URL is the best thing to parse I later realized I needed to know if a user is connected over HTTPS or HTTP(localhost).

I have a doubt. Someone please help me fix this.
Context: I am trying to implement a Saas, custom domain, multi tenant.

ref https://github.com/elixir-ecto/ecto/blob/master/guides/howtos/Multi%20tenancy%20with%20foreign%20keys.md#setting-org_id-by-default

My Code

 defmodule Atmanirbhar.Repo do
  ..........
    @tenant_key {__MODULE__, :org_id}

  def put_org_id(org_id) do
    Process.put(@tenant_key, org_id)
  end

  def get_org_id() do
    Process.get(@tenant_key)
  end

  def default_options(_operation) do
    [org_id: get_org_id()]
  end

  def prepare_query(operation, query, opts) do
    IO.puts "opts has org id?"
    IO.puts inspect(opts)
    cond do
      opts[:skip_org_id] -> {query, opts}

      org_id = opts[:org_id] ->
        {Ecto.Query.where(query, org_id: ^org_id), opts}

      true ->
        raise "expected org_id or skip_org_id to be set"
    end
  end


end

   In pageLive.ex,
  
 def handle_params(params, url, socket) do
    host_name =  URI.parse(url).host
    Atmanirbhar.Repo.put_org_id(host_name)
# The value gets set somewhere else….,
# Repo.get_org_id returns nil
     {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end  
# vs
    def mount(params, session, socket) do

   Atmanirbhar.Repo.put_org_id(123)
# The value get set here,
# Repo.get_org_id returns value set here … I.e 123 

    deals = Atmanirbhar.Marketplace.list_deals_for_pincode(pincode)
  
    {:ok, assign(socket, ... )}
  end
 
What I need .... find correct hostname and so the tenant_id/org_id and tenant results..
Should I set it in mount or handle_params, if in mount, any straightforward way to get host?
or help me figure out what should be modified...

Hi sandeshoni, have you found answer for your question?

My initial thought is to get org_id from mount, when the live view page is mounted and data can be loaded from db. Is that what you need?