bian2510

bian2510

Hi guys I’m having troubles with one preload.

I’m creating one property and I’m adding preloads, but when not have any register for has_one association is returning nil and through this error

     ** (RuntimeError) cannot encode association :address from MyApp.Model.Property to JSON because the association was not loaded.
     
     You can either preload the association:
     
         Repo.preload(MyApp.Model.Property, :address)
     
     Or choose to not encode the association when converting the struct to JSON by explicitly listing the JSON fields in your schema:
     
         defmodule MyApp.Model.Property do
           # ...
     
           @derive {Jason.Encoder, only: [:name, :title, ...]}
           schema ... do

I’ve print the Property created and looks like this

%MyApp.Model.Property{
  __meta__: #Ecto.Schema.Metadata<:loaded, "properties">,
  address: nil,
  currency: "USD",
  description: "Depto 2 ambientes",
  id: 908,
  inserted_at: ~N[2021-05-14 15:29:52],
  price: 260000,
  property_features: nil,
  property_images: [],
  property_type: "department",
  spaces: 2,
  status: true,
  subscriptions: [],
  updated_at: ~N[2021-05-14 15:29:52],
  user: #Ecto.Association.NotLoaded<association :user is not loaded>,
  user_id: 3093
}

I think that this could be for the nil returned in the property?

This is my function to create the property.

  def create_property(user) do
    Repo.insert!(%Property{
      description: "Depto 2 ambientes",
      price: 260_000,
      currency: "USD",
      spaces: 2,
      status: true,
      property_type: "department",
      user_id: user.id
    }) |> Repo.preload([:address, :subscriptions, :property_features, :property_images]) |> IO.inspect
  end

and this is the schema in property.ex

  @derive {Jason.Encoder, except: [:__meta__, :inserted_at, :updated_at, :user]}

  schema "properties" do
    field :spaces, :integer
    field :currency, :string
    field :description, :string
    field :price, :integer
    field :property_type, :string
    field :status, :boolean, default: false
    belongs_to :user, User
    has_one :address, Address
    has_one :property_features, PropertyFeatures
    has_many :subscriptions, Subscription
    has_many :property_images, PropertyImages

    timestamps()
  end

Any have idea where is the problem?

Showing Posts 1 to 8

dimitarvp

dimitarvp

What does your database say? Does that property object actually have linked address?

al2o3cr

al2o3cr

There’s something odd going on - the printout shows nil in address, but the error message is from inside a protocol implementation for Ecto.Association.NotLoaded:
https://github.com/elixir-ecto/ecto/blob/74a85a99b6dc0fc4667876d5341ad4cafceaa9f6/lib/ecto/json.ex#L2-L6

The code in create_property looks like it should return a correctly loaded association (nil is still “loaded”, just empty), so the next place to investigate is where the result from create_property is used.

bian2510

bian2510 OP

is used in a test:

user_controller_text.exs

    test "return an array with properties", %{conn: conn} do
      user_1 = UserControllerTest.create_user()
      user_2 = UserControllerTest.create_user()
      create_property(user_1)
      create_property(user_2)
      conn = get(conn, Routes.property_path(conn, :index))
      assert conn.status == 200

      assert [
               %{
                 "address" => _address,
                 "currency" => _currency,
                 "description" => _description,
                 "id" => _id,
                 "price" => _price,
                 "property_type" => _property_type,
                 "spaces" => _spaces,
                 "status" => _status,
                 "subscriptions" => [],
                 "user_id" => _user_id
               },
               %{
                 "address" => _address2,
                 "currency" => _currency2,
                 "description" => _description2,
                 "id" => _id2,
                 "price" => _price2,
                 "property_type" => _property_type2,
                 "property_features" => _property_features2,
                 "spaces" => _spaces2,
                 "status" => _status2,
                 "subscriptions" => [],
                 "user_id" => _user_id2
               }
             ] = Jason.decode!(conn.resp_body)
    end

This is property_controller.ex

defmodule MyAppWeb.PropertyController do
  use MyAppWeb, :controller

  alias MyApp.CrudBase
  alias MyApp.Model.Property

  def index(conn, _params) do
    json(conn, CrudBase.all(Property, [:address, :subscriptions, :property_features, :property_images]))
  end
end

crud_base.ex

defmodule MyApp.CrudBase do
  alias MyApp.Repo
  alias MyApp.Errors.ErrorHandler

  def all(model, preloads) do
    Repo.all(model) |> Repo.preload([preloads])
  end
end
al2o3cr

al2o3cr

I suspect the extra [ ] around preloads here is confusing Repo.preload.

bian2510

bian2510 OP

Yes this is the solution for this test. Thanks. But I’ve other test that is failing could you please help me with this?

this is the update method

test "return property when data is valid", %{conn: conn} do
      user = UserControllerTest.create_user()
      property = create_property(user)
      property_param = @update_attrs |> put_in(["user_id"], property.id)

      conn =
        UserControllerTest.sigin_and_put_token(conn, user)
        |> put(Routes.property_path(conn, :update, property.id), property: property_param)

      assert 200 = conn.status
      assert {:ok, property_updated} = Jason.decode(conn.resp_body)

      updated_description = @update_attrs["description"]
      updated_price = @update_attrs["price"]
      updated_currency = @update_attrs["currency"]
      updated_spaces = @update_attrs["spaces"]

      assert %{
               "address" => _address,
               "id" => _user_id,
               "description" => _description,
               "price" => _price,
               "currency" => _currency,
               "spaces" => _spaces,
               "property_type" => _property_type
             } = property_updated

      assert updated_description == property_updated["description"]
      assert updated_price == property_updated["price"]
      assert updated_currency == property_updated["currency"]
      assert updated_spaces == property_updated["spaces"]
end

this is the update function in the property_controller.ex

  def update(conn, %{"id" => id, "property" => property_params}) do
    CrudBase.update(Property, id, property_params, [:address, :subscriptions, :property_features, :property_images])
    |> case do
      %Property{} = property -> json(conn, property)
      {:error, error} -> conn |> put_status(400) |> json(%{error: error})
    end
  end

this is the update method in my crud_base.ex

  def update(model, id, attrs, preloads) do
    changeset = Repo.get!(model, id) |> model.changeset_update(attrs)
    IO.inspect(preloads, label: model)
    case changeset.valid? do
      true -> Repo.update!(changeset) |> Repo.preload(preloads)
      false -> {:error, ErrorHandler.changeset_error_to_map(changeset)}
    end
  end

and this is the changeset

  def changeset_update(property, attrs) do
    property
    |> cast(attrs, [:description, :price, :currency, :spaces, :property_type])
  end

The endpoint is working but the test fail with the same error I can’t identify the error.

You have any idea?

** (RuntimeError) cannot encode association :address from MyApp.Model.Property to JSON because the association was not loaded.
     
     You can either preload the association:
     
         Repo.preload(MyApp.Model.Property, :address)
     
     Or choose to not encode the association when converting the struct to JSON by explicitly listing the JSON fields in your schema:
     
         defmodule MyApp.Model.Property do
           # ...
     
           @derive {Jason.Encoder, only: [:name, :title, ...]}
           schema ... do
     

bian2510

bian2510 OP

The problem is here because if I try get and user with properties created need the preload to show this complete entity.

  def create_user() do
    Repo.insert!(%User{
      name: "Fabian",
      last_name: "Hernandez",
      phone: random_num(),
      email: "bian#{random_num()}@gmail.com",
      photo: "unaphoto",
      document: random_num(),
      document_type: "DNI",
      password: Bcrypt.hash_pwd_salt("password"),
      type: :client
    })
    |> Repo.preload([:properties])
  end

When I try of return one user with properties and this properties not have the preloads

here is the example

%MyApp.Model.User{
  __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
  document: 798048377,
  document_type: "DNI",
  email: "bian264519099@gmail.com",
  id: 3973,
  inserted_at: ~N[2021-05-15 04:34:59],
  last_name: "Hernandez",
  name: "Fabian",
  password: "$2b$04$GTA9i8JvQEpUVCKLx5l6Kuo9BtUa1KCbOoJ3rhXZpqMUa3Reob4Y2",
  phone: 953856669,
  photo: "unaphoto",
  properties: [
    %MyApp.Model.Property{
      __meta__: #Ecto.Schema.Metadata<:loaded, "properties">,
      address: #Ecto.Association.NotLoaded<association :address is not loaded>,
      currency: "USD",
      description: "Depto 2 ambientes",
      id: 1108,
      inserted_at: ~N[2021-05-15 04:34:59],
      price: 260000,
      property_features: #Ecto.Association.NotLoaded<association :property_features is not loaded>,
      property_images: #Ecto.Association.NotLoaded<association :property_images is not loaded>,
      property_type: "department",
      spaces: 2,
      status: true,
      subscriptions: #Ecto.Association.NotLoaded<association :subscriptions is not loaded>,
      updated_at: ~N[2021-05-15 04:34:59],
      user: #Ecto.Association.NotLoaded<association :user is not loaded>,
      user_id: 3973
    }
  ],
  type: :client,
  updated_at: ~N[2021-05-15 04:34:59]
}

The question is. How I could preload the attrs of the property from this place?

al2o3cr

al2o3cr

Repo.preload can handle nested associations. If you need the properties for that User to have a loaded address association, you’d write something like:

|> Repo.preload([properties: [:address]])
bian2510

bian2510 OP

Thank you very much for the help, with this I was able to fix the error.
:slight_smile:

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews