Login fails after setting multi tenancy

Hi, thank for your help in advance.

I’m building a new app with phoenix and live view

I’m trying to build a multi tenant app and I followed Ecto’s guide for multi tenancy with foreign keys.

But after implementing it, log in failed

So I went to get_user_by_email_and_password and set skip_user_id as instructed in the guide

  def get_user_by_email_and_password(email, password)
      when is_binary(email) and is_binary(password) do
    user = Repo.get_by(User, email: email, skip_user_id: true)
    if User.valid_password?(user, password), do: user

In case the Repo code is helpful, here it is

defmodule TestApp.Repo do
  use Ecto.Repo,
    otp_app: :test_app,
    adapter: Ecto.Adapters.Postgres

  require Ecto.Query

  @impl true
  def prepare_query(_operation, query, opts) do
    cond do
      opts[:skip_user_id] || opts[:schema_migration] ->
        {query, opts}

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

      true ->
        raise "expected user_id or skip_user_id to be set"

  @tenant_key {__MODULE__, :user_id}

  def put_user_id(user_id) do
    Process.put(@tenant_key, user_id)

  def get_user_id() do

  @impl true
  def default_options(_operation) do
    [user_id: get_user_id()]

Any clue of what is happening here?

This is the issue, you are sending ‘skip_user_id’ as a filter for the query instead of as an option.

Try wrapping ‘[email: email]’ and ‘[skip_user_id: true]’ in block quotes to separate the clauses from the options.

1 Like

I think just making it one kw list would work:

user = Repo.get_by(User, [email: email, skip_user_id: true])

1 Like
Repo.get_by(User, [email: email, skip_user_id: true])

is equivalent to

Repo.get_by(User, email: email, skip_user_id: true)

Both cases are calling Repo.get_by/2. OP needs to call Repo.get_by/3 as per what @hlx said.

1 Like

Thanks for the correction. I’ll have be more careful in the future. :slight_smile:

Thank you very much. I’ve just learned that if the last argument is a list it doesn’t need to be in [ … ]