Search code examples
elixirphoenix-frameworkecto

Preloaded data lost when turned into JSON


in my context I have the below to preload owner and assignee both which belong to users

  def list_tasks do
    Repo.all(Task)
    |> Repo.preload([:owner, :assignee])
  end

in my controller for index I have something like this:

def index(conn, _params) do
    tasks = Issue.list_tasks()
    IO.inspect(tasks)
    render(conn, "index.json", tasks: tasks)
end

the IO.inspect(tasks) prints out

[
  %Task3.Issue.Task{
    __meta__: #Ecto.Schema.Metadata<:loaded, "tasks">,
    assignee: %Task3.Accounts.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      email: "[email protected]",
      id: 2,
      inserted_at: ~N[2018-04-02 18:22:21.699478],
      updated_at: ~N[2018-04-02 18:22:21.699486],
      username: "Jill"
    },
    assignee_id: 2,
    details: nil,
    id: 1,
    inserted_at: ~N[2018-04-02 18:22:21.711588],
    owner: %Task3.Accounts.User{
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      email: "[email protected]",
      id: 1,
      inserted_at: ~N[2018-04-02 18:22:21.677877],
      updated_at: ~N[2018-04-02 18:22:21.677887],
      username: "Jack"
    },
    owner_id: 1,
    status: "COMPLETE",
    timespent: nil,
    title: "test",
    updated_at: ~N[2018-04-02 18:22:21.711598]
  }
]

However the json data I get on the front end is

{"data":[{"title":"test","timespent":null,"status":"COMPLETE","id":1,"details":null}]}

I have lost assignee and owner. Am I missing anything? Was there an extra step to be taken to get the preloaded data to json form?


Solution

  • You need to check your task_view.ex file

    If it's the default file generated with phx.gen.json it'll look something like this:

    defmodule MyAppWeb.TaskView do
        use MyAppWeb, :view
        alias MyAppWeb.TaskView
    
        def render("index.json", %{tasks: tasks}) do
            %{data: render_many(tasks, TaskView, "task.json")}
        end
    
        def render("show.json", %{task: task}) do
            %{data: render_one(task, TaskView, "task.json")}
        end
    
        def render("task.json", %{task: task}) do
            %{
                id: task.id,
                title: task.title,
                timespent: task.timespent,
                details: task.details,
                status: task.status
            }
        end
    end
    

    You need to edit this file and add the extra fields you want to show.

    e.g. for assignee you could reuse your autogenerated view like this:

    defmodule MyAppWeb.TaskView do
        use MyAppWeb, :view
        alias MyAppWeb.{TaskView, AsigneeView}
    
        ...
    
        def render("task.json", %{task: task} do
            %{
                id: task.id,
                ...
                asignee: render_one(task.asignee, AsigneeView, "asignee.json"),
            }
        end
    end