#How do you conditionally render associations?

5 messages · Page 1 of 1 (latest)

tulip locust
#

In the first case I want to return the associations in the response.

In the calls to render(conn, :index, criteria: criteria) and render(conn, :show, criterion: criterion), I was hoping to catch the difference of the output using when guards:

  def data(%Criterion{} = criterion)
      when is_map(criterion.program) and is_map(criterion.variant) do
    %{
      id: criterion.id,
      code: criterion.code,
      name: criterion.name,
      ...
      program_id: criterion.program_id,
      program: CockpitWeb.ProgramJSON.data(criterion.program),
      variant_id: criterion.variant_id,
      variant: CockpitWeb.VariantJSON.data(criterion.variant)
    }
  end

  def data(%Criterion{} = criterion) do
    %{
      id: criterion.id,
      code: criterion.code,
      name: criterion.name,
      ...
      program_id: criterion.program_id,
      variant_id: criterion.variant_id
    }
  end
#

But it doesn't seem to do the trick:

[debug] Processing with CockpitWeb.CriterionController.show/2
  Parameters: %{"id" => "d1c71cea-2bd9-41dd-aa0b-968230a7bede"}
  Pipelines: [:api]
[debug] QUERY OK source="criteria" db=0.4ms idle=200.7ms
SELECT c0."id", c0."code", c0."name", ... , c0."program_id", c0."variant_id", c0."inserted_at", c0."updated_at" FROM "criteria" AS c0 WHERE (c0."id" = $1) ["d1c71cea-2bd9-41dd-aa0b-968230a7bede"]
↳ CockpitWeb.CriterionController.show/2, at: lib/cockpit_web/controllers/criterion_controller.ex:24
[info] Sent 500 in 19ms
[error] ** (FunctionClauseError) no function clause matching in CockpitWeb.ProgramJSON.data/1
    (cockpit 0.1.0) lib/cockpit_web/controllers/program_json.ex:18: CockpitWeb.ProgramJSON.data(#Ecto.Association.NotLoaded<association :program is not loaded>)
    (cockpit 0.1.0) lib/cockpit_web/controllers/criterion_json.ex:34: CockpitWeb.CriterionJSON.data/1
    (cockpit 0.1.0) lib/cockpit_web/controllers/criterion_json.ex:15: CockpitWeb.CriterionJSON.show/1
#

I could rename the first function data_with_assoc and using it accordingly, but I'm not sure I'm doing the right thing here..

frozen spade
#

in lib/cockpit_web/controllers/program_json.ex:18 you are passing in an #Ecto.Association.NotLoaded<association :program is not loaded> struct. You need to manually handle this, or if you expect the association to always be there, you need to use Repo.preload

tulip locust
# frozen spade in `lib/cockpit_web/controllers/program_json.ex:18` you are passing in an `#Ecto...

this is what i do, but only in the case of the list:

def list_criteria(params) do
    query =
      from c in Criterion,
        join: p in assoc(c, :program),
        join: v in assoc(c, :variant),
        preload: [program: p, variant: v]

    query
    |> maybe_filter_by_program(params)
    |> maybe_filter_by_variant(params)
    |> Repo.all()
  end

  defp maybe_filter_by_program(query, params) do
    case params["program_id"] do
      nil ->
        query

      program_id ->
        where(query, [c], c.program_id == ^program_id)
    end
  end

  defp maybe_filter_by_variant(query, params) do
    case params["variant_id"] do
      nil ->
        query

      variant_id ->
        where(query, [c], c.variant_id == ^variant_id)
    end
  end

  def get_criterion!(id), do: Repo.get!(Criterion, id)