Hello,
I have an app with user login system created with phx.gen.auth. There is a router plug which uses fetch_current_user() function to fetch user on every load. Every user also has a profile in another table so when a user loads, it also preloads its profile.
user_auth.ex
def fetch_current_user(conn, _opts) do
{user_token, conn} = ensure_user_token(conn)
user = user_token && Accounts.get_user_by_session_token(user_token)
user = Repo.preload(user, [:profile])
conn
|> assign(:current_user, user)
end
user.ex
schema "users" do
...fields...
has_one :profile, Profile
end
Profiles doesn’t have id field, instead they use user_id as primary key.
profile.ex
@primary_key {:user_id, :integer, autogenerate: false}
schema "profiles" do
field :name, :string
...other fields
embeds_one :image, ProfileImageEmbed, on_replace: :update
belongs_to :user, User, define_field: false
timestamps()
end
user_token.ex
def verify_session_token_query(token) do
query =
from token in token_and_context_query(token, "session"),
join: user in assoc(token, :user),
where: token.inserted_at > ago(@session_validity_in_days, "day"),
select: user
{:ok, query}
end
This code works as expected but every time a page loads, it creates two queries, one for user_token which joins a user to user_token, and another query to preload user profile.
I would like to optimize this and use only one query to get both the user and their profile. I think I should use join to do that. I’m a beginner and I have a little bit of problem understanding when exactly should I use joins and when should I use preloads so if someone could give me some general guidance when is one better then the other, I would be very grateful.
user_token.ex
def verify_session_token_query(token) do
query =
from token in token_and_context_query(token, "session"),
join: user in assoc(token, :user),
join: profile in assoc(user, :profile),
where: token.inserted_at > ago(@session_validity_in_days, "day"),
select: {user, profile.name, profile.image}
{:ok, query}
end
So, I removed profile preload from fetch_current_user() and added join to user.token.ex. For some reason I’m getting an error.
key :id not found in: {#MyApp.Accounts.User<__meta__: #Ecto.Schema.Metadata<:loaded, "users">, id: 1, , email: ....
Can someone help me with this?