Help understanding preload and queries in Ecto

Hello, I’m pretty new to Elixir and am having some confusion about how all of this Ecto stuff works. Say I have 2 models, Company and Employee.

defmodule Project.Employee do
  use Project.Web, :model

  schema "employee" do
    field :name, :string
    belongs_to :company, Project.Company
  end
end
defmodule Project.Company do
  use Project.Web, :model

  schema "company" do
    field: name, :string
    belongs_to :user, Project.User
    has_many :employees, Project.Employee  
  end

  def preload_all(query) do
    from c in query, preload: [:user, :employees]
  end
end

and then in the Project.Company controller I have

def show(conn, %{"id" => company_id}) do
  current_user = Guardian.Plug.current_resource(conn)
  
  company = current_user
    |> assoc(:companies)
    |> Company.preload_all
    |> Repo.get(company_id)
  ...
end

I got the general structure of all of this through a tutorial, and I’m finding that I don’t understand the preload and query logic as well as I thought. It seems that :user is being preloaded just fine, but :employees is not. Does anyone have any idea why, or can shed some wisdom on how it works? Here’s how I have it worked out in my head.

  1. current_user is loaded from Guardian

  2. assoc(:companies) returns a Ecto query that looks something like from Project.Company where user_id = {{current_user id}}

  3. That query is then sent into Project.preload_all. preload_all returns another query that returns every Company for a user, with all of the :user and :candidate data loaded.

  4. That query is sent to Repo.get(project_id) which runs that query and then matches the results with the company_id given, returning just that one Company.

But with what I have, the :employees data isn’t being loaded. Any help at all, including just correcting my knowledge of how this is working is appreciated. thanks!

Ugh, well it turns out the answer was just a stupid mistake and had nothing to do with Ecto. I forgot to update my Poison encoder to include :employees

@derive {Poison.Encoder, only: [..., :employees]}

However, any help with my understanding of it all is still appreciated :).

I am unsure why the @derive bit was necessary for you unless the error was actually in your View to JSON or so instead of in the posted code, however we can help with questions you may have. :slight_smile: