How To: Ecto Query using multiple join and select_merge, rendered to a LiveComponent

Learned how to do an Ecto multiple join and multiple select_merge, to create a hybrid selection from 3 different tables, using virtual struct fields, and how to render those values in a LiveComponent. In this case the user_student virtual field is another struct from the users table.

Query Function:

  # ---------------
  # get_class_students
  # ---------------
  def get_class_students(class_id) do
    Repo.all(
      from s in Student,
        join: cs in ClassStudent,
        on: cs.student_id == s.id and cs.class_id == ^class_id,
        join: u in User,
        on: u.id == s.user_id,
        select_merge: %{class_student: cs},
        select_merge: %{user_student: u},
        order_by: [s.id]
    )
  end

Schema:

  schema "students" do
    field :guardian_email, :string
    field :report_enabled, :boolean, default: false  # require guardian e-mail address to be able to enable
    field :phone_number, :string

    field :user_student, :any, virtual: true
    field :class_student, :any, virtual: true
    field :student_event, :any, virtual: true
    
    timestamps()
  end

HEEx:

      <div class="flex-col gap-4">
        <%= for student <- @students do %>
          <.live_component module={MyAppWeb.Components.Student} id={"guardian-#{student.id}"} student={student} />
        <% end %>
      </div>

LiveComponent (using user_student virtual field):

<div class="flex flex-row shadow-md flex-grow border-solid border mb-4 p-2 rounded-md hover:shadow-mdh hover:border-brand-color" id={@id}>
  <div class="flex-col">
    <div>
      <%= if @student.user_student.middle_initial do %>
        <%= @student.user_student.first_name %> <%= @student.user_student.middle_initial %>. <%= @student.user_student.last_name %>
      <% else %>
        <%= @student.user_student.first_name %> <%= @student.user_student.last_name %>
      <% end %>
    </div>
  </div>
  <div class="ml-auto order-2">
    <i class="las la-ellipsis-v"></i>
  </div>
</div>