vt-elixir / ja_serializer

JSONAPI.org Serialization in Elixir.
Other
640 stars 148 forks source link

Serializer not loaded relationships model #334

Closed JamesAndresCM closed 4 years ago

JamesAndresCM commented 4 years ago

Hi, i trying to load relationships in my user view serializer, but i can't results.

Query:

def get_user!(id) do
    from(u in User,join: a in assoc(u, :account), 
          where: u.id == ^id,
          preload: [account: u], join: l in assoc(u, :linked_users),
          where: u.id == l.parent_id , preload: [linked_users: u],
          where: l.active == true) |> Repo.one
  end

Controller:

def show(conn, %{"id" => id}) do
    user = Users.get_user!(id)
    render(conn, "show.json-api", data: user, opts: [include: "account"])
  end

And View:

defmodule AccountServiceWeb.UserView do
  use AccountServiceWeb, :view
  use JaSerializer.PhoenixView

  attributes [:id,
  :username,
  :email,
  :old_encrypted_password,
  ....]

  has_one :account,
    serializer: AccountServiceWeb.AccountView,
    include: true,
    type: :account

But Json only display User Model :

{
   "jsonapi":{
      "version":"1.0"
   },
   "data":{
      "type":null,
      "relationships":{
         "account":{
            "data":{
               "type":null,
               "id":"1327"
            }
         }
      },
      "id":"1327",
      "attributes":{
         "updated-at":"2020-03-31T20:01:50Z",
         "account-id":1,
         "salt":null,
         "locked-at":null,
         "last-sign-in-at":"2020-03-18T20:31:54Z",
         "support":0,
         "holding-id":null,
         "old-encrypted-password":null,
         "last-seen":"2020-03-31T20:01:50Z",
         "reset-password-token":null,
         "created-at":"2015-07-09T17:09:48Z",
         "lastname":"Grass",
         "email":"noname@xx",
         "reset-password-sent-at":null,
         "activation-token":null,
         "reset-token":null,
         "can-modify":true,
         "name":"Andres Colonia",
         "theme":0,
         "new-layout":true,
         "current-sign-in-at":"2020-03-18T20:34:19Z",
         "current-sign-in-ip":"::1",
         "can-create-users":true,
         "type":null,
         "sign-in-count":583,
         "confirmed-at":"2016-12-01T19:48:47Z",
         "active":true,
         "account-user":null,
         "confirmation-token":null,
         "can-modify-data":true,
         "role":"admin",
         "remember-created-at":null,
         "id":1327,
         "password-changed-at":"2019-08-19T14:56:52Z",
         "show-chat":true,
         "encrypted-password":"$2a$10$jkSngSCBYowAgYSTsmBAseOVmYGMDWIN2uPpk69tC4WKIs8291YQK",
         "level":262141,
         "enable-summary-report":false,
         "phone":"+56978197220",
         "change-password":false,
         "username":"test",
         "binary-permissions":255,
         "failed-attempts":0,
         "last-sign-in-ip":"::1",
         "binary-authorization":255,
         "profile-picture":null
      }
   }
}

What's it's wrong? If i use your doc, the examples only show preload without conditions, but i can't found nothing about preload query relationships.

beerlington commented 4 years ago

It looks like you might be preloading the users into the account relationship. The user id and account id are the same in the response, which seems suspicious.

Does it work if you change the account preload in your query? Change preload to preload: [account: a]

def get_user!(id) do
    from(u in User,join: a in assoc(u, :account), 
          where: u.id == ^id,
          preload: [account: a], join: l in assoc(u, :linked_users),
          where: u.id == l.parent_id , preload: [linked_users: u],
          where: l.active == true) |> Repo.one
  end
JamesAndresCM commented 4 years ago

It looks like you might be preloading the users into the account relationship. The user id and account id are the same in the response, which seems suspicious.

Does it work if you change the account preload in your query? Change preload to preload: [account: a]

def get_user!(id) do
    from(u in User,join: a in assoc(u, :account), 
          where: u.id == ^id,
          preload: [account: a], join: l in assoc(u, :linked_users),
          where: u.id == l.parent_id , preload: [linked_users: u],
          where: l.active == true) |> Repo.one
  end

Thanks for your fast reply

This is the output query:

 us = from u in User,join: a in assoc(u, :account), where: u.id == 1327, join: l in assoc(u, :linked_users), where: u.id == l.parent_id , where: l.active == true, preload: [account: u, linked_users: u]
#Ecto.Query<from u0 in AccountService.Accounts.User,
 join: a1 in assoc(u0, :account), join: l2 in assoc(u0, :linked_users),
 where: u0.id == 1327, where: u0.id == l2.parent_id, where: l2.active == true,
 preload: [linked_users: u0, account: u0]>
iex(84)> Repo.all(us)
[debug] QUERY OK source="users" db=5.1ms idle=9121.0ms
SELECT u0.`id`, u0.`account_id`, u0.`username`, u0.`email`, u0.`old_encrypted_password`, u0.`salt`, u0.`reset_token`, u0.`activation_token`, u0.`active`, u0.`created_at`, u0.`updated_at`, u0.`type`, u0.`role`, u0.`name`, u0.`lastname`, u0.`holding_id`, u0.`can_create_users`, u0.`binary_authorization`, u0.`can_modify`, u0.`profile_picture`, u0.`last_seen`, u0.`new_layout`, u0.`reset_password_token`, u0.`remember_created_at`, u0.`sign_in_count`, u0.`current_sign_in_at`, u0.`last_sign_in_at`, u0.`current_sign_in_ip`, u0.`last_sign_in_ip`, u0.`failed_attempts`, u0.`locked_at`, u0.`password_changed_at`, u0.`change_password`, u0.`level`, u0.`can_modify_data`, u0.`confirmation_token`, u0.`confirmed_at`, u0.`support`, u0.`show_chat`, u0.`theme`, u0.`phone`, u0.`enable_summary_report`, u0.`binary_permissions`, u0.`encrypted_password`, u0.`id`, u0.`account_id`, u0.`username`, u0.`email`, u0.`old_encrypted_password`, u0.`salt`, u0.`reset_token`, u0.`activation_token`, u0.`active`, u0.`created_at`, u0.`updated_at`, u0.`type`, u0.`role`, u0.`name`, u0.`lastname`, u0.`holding_id`, u0.`can_create_users`, u0.`binary_authorization`, u0.`can_modify`, u0.`profile_picture`, u0.`last_seen`, u0.`new_layout`, u0.`reset_password_token`, u0.`remember_created_at`, u0.`sign_in_count`, u0.`current_sign_in_at`, u0.`last_sign_in_at`, u0.`current_sign_in_ip`, u0.`last_sign_in_ip`, u0.`failed_attempts`, u0.`locked_at`, u0.`password_changed_at`, u0.`change_password`, u0.`level`, u0.`can_modify_data`, u0.`confirmation_token`, u0.`confirmed_at`, u0.`support`, u0.`show_chat`, u0.`theme`, u0.`phone`, u0.`enable_summary_report`, u0.`binary_permissions`, u0.`encrypted_password`, u0.`id`, u0.`account_id`, u0.`username`, u0.`email`, u0.`old_encrypted_password`, u0.`salt`, u0.`reset_token`, u0.`activation_token`, u0.`active`, u0.`created_at`, u0.`updated_at`, u0.`type`, u0.`role`, u0.`name`, u0.`lastname`, u0.`holding_id`, u0.`can_create_users`, u0.`binary_authorization`, u0.`can_modify`, u0.`profile_picture`, u0.`last_seen`, u0.`new_layout`, u0.`reset_password_token`, u0.`remember_created_at`, u0.`sign_in_count`, u0.`current_sign_in_at`, u0.`last_sign_in_at`, u0.`current_sign_in_ip`, u0.`last_sign_in_ip`, u0.`failed_attempts`, u0.`locked_at`, u0.`password_changed_at`, u0.`change_password`, u0.`level`, u0.`can_modify_data`, u0.`confirmation_token`, u0.`confirmed_at`, u0.`support`, u0.`show_chat`, u0.`theme`, u0.`phone`, u0.`enable_summary_report`, u0.`binary_permissions`, u0.`encrypted_password` FROM `users` AS u0 INNER JOIN `accounts` AS a1 ON a1.`id` = u0.`account_id` INNER JOIN `linked_users` AS l2 ON l2.`parent_id` = u0.`id` WHERE (u0.`id` = 1327) AND (u0.`id` = l2.`parent_id`) AND (l2.`active` = TRUE) []
[
  %AccountService.Accounts.User{
    profile_picture: nil,
    confirmation_token: nil,
    users: #Ecto.Association.NotLoaded<association :users is not loaded>,
    current_sign_in_ip: "::1",
    updated_at: ~U[2020-03-31 20:01:50Z],
    type: nil,
    reset_password_token: nil,
    current_sign_in_at: ~U[2020-03-18 20:34:19Z],
    can_modify_data: true,
    activation_token: nil,
    holding_id: nil,
    active: true,
    password_changed_at: ~U[2019-08-19 14:56:52Z],
    account_id: 1,
    reset_token: nil,
    name: "Andres",
    can_create_users: true,
    created_at: ~U[2015-07-09 17:09:48Z],
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    phone: "+56978197220",
    lastname: "Grass",
    account: %AccountService.Accounts.User{
      profile_picture: nil,
      confirmation_token: nil,
      users: #Ecto.Association.NotLoaded<association :users is not loaded>,
      current_sign_in_ip: "::1",
      updated_at: ~U[2020-03-31 20:01:50Z],
      type: nil,
      reset_password_token: nil,
      current_sign_in_at: ~U[2020-03-18 20:34:19Z],
      can_modify_data: true,
      activation_token: nil,
      holding_id: nil,
      active: true,
      password_changed_at: ~U[2019-08-19 14:56:52Z],
      account_id: 1,
      reset_token: nil,
      name: "Andres",
      can_create_users: true,
      created_at: ~U[2015-07-09 17:09:48Z],
      __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
      phone: "+56978197220",
      lastname: "Grass",
      account: #Ecto.Association.NotLoaded<association :account is not loaded>,
      email: "andres@gmail.com",
      enable_summary_report: false,
      encrypted_password: "$2a$10$jkSngSCBYowAgYSTsmBAseOVmYGMDWIN2uPpk69tC4WKIs8291YQK",
      id: 1327,
      confirmed_at: ~U[2016-12-01 19:48:47Z],
      ...
    },
    email: "andres@gmail.com",
    enable_summary_report: false,
    encrypted_password: "$2a$10$jkSngSCBYowAgYSTsmBAseOVmYGMDWIN2uPpk69tC4WKIs8291YQK",
    id: 1327,
    confirmed_at: ~U[2016-12-01 19:48:47Z],
    binary_permissions: 255,
    change_password: false,
    linked_users: [
      %AccountService.Accounts.User{
        profile_picture: nil,
        confirmation_token: nil,
        users: #Ecto.Association.NotLoaded<association :users is not loaded>,
        current_sign_in_ip: "::1",
        updated_at: ~U[2020-03-31 20:01:50Z],
        type: nil,
        reset_password_token: nil,
        current_sign_in_at: ~U[2020-03-18 20:34:19Z],
        can_modify_data: true,
        activation_token: nil,
        holding_id: nil,
        active: true,
        password_changed_at: ~U[2019-08-19 14:56:52Z],
        account_id: 1,
        reset_token: nil,
        name: "Andres",
        can_create_users: true,
        created_at: ~U[2015-07-09 17:09:48Z],
        ...
      }
    ],
    remember_created_at: nil,
    new_layout: true,
    binary_authorization: 255,
    theme: 0,
    locked_at: nil,
    last_seen: ~U[2020-03-31 20:01:50Z],
    last_sign_in_at: ~U[2020-03-18 20:31:54Z],
    username: "test",
    can_modify: true,
    last_sign_in_ip: "::1",
    role: "admin",
    old_encrypted_password: nil,
    failed_attempts: 0,
    level: 262141,
    support: 0,
    show_chat: true,
    sign_in_count: 583,
    salt: nil
  }
]

And this works me

def get_user!(id) do
    user = Repo.get(User, id) 
    user |> Repo.preload(account: from(u in Account))
    |> Repo.preload(linked_users: from(l in LinkedUser, where: ^id == l.parent_id and l.active == true))
  end

But why query not serialize relationships? Regards

beerlington commented 4 years ago

account: %AccountService.Accounts.User{

That does not look right. I would expect the account relationship to use a different schema from the User.

JamesAndresCM commented 4 years ago

account: %AccountService.Accounts.User{

That does not look right. I would expect the account relationship to use a different schema from the User.

Thanks, now this work, i change preload, but another question, why type relationships is null?

type: null
 has_one :account,
    serializer: AccountServiceWeb.AccountView,
    include: true,
    type: :account,
    identifiers: :when_included