Nested embeded schemas

Hello guys!
I wanna do the scheme that can represent my JSON structure, I mean:
{
data,
settings: {
time_of_occurance: {
min,
max
}
}
}

And I cannot handle it. It seems to Ecto has problems with embeded_schema (settings) which contains another embeded_schema (time_of_occurance).

I get this error all the time, when I try to add time_of_occurance schema:
(RuntimeError) casting embeds with cast/4 is not supported, use cast_embed/3 instead

My code: https://pastebin.com/NWyfNejb

What am I doin wrong?

Not sure how your code even gets to that error because according to Ecto.Schema.embeds_one docs on inline embedded schema modules, you are supposed to also specify a module name – not only an atom designating the name of the embed.

Meaning that this:

    embeds_one :time_of_occurance do

should not even compile. I’d expect it to be like this:

    embeds_one :time_of_occurance, TimeOfOccurance do

I assume your error is otherwise inside the time_of_occurance_changeset function. I can’t think of anything smart to help except maybe to just promote that embedded schema to its full-blown module and see if that fixes it?

(BTW, please use the triple backticks (```) syntax to enclose code, meaning (1) triple backticks, (2) new line, (3) your code, (4) new line, (5) triple backticks again.)

1 Like

I added TimeOfOccurance module name and also created TimeOfOccurance module. Both didnt work. Any other idea? Or any sample of nested embeded schemas? I cant find them, so also I wondering whether its a good option.

*I have the same error when I use cast_assoc

You don’t need an extra TimeOfOccurance module if you decided to declare it inline. @dimitarvp suggested a single line change which will at the end look like

defmodule AngotiaCatalogsApi.NPCS.Settings do
  use Ecto.Schema
  import Ecto.Changeset

  embedded_schema do
    embeds_one :time_of_occurance, TimeOfOccurance do
      field :min, :integer
      field :max, :integer
    end
  end

  def settings_changeset(settings, attrs) do
    settings
    |> cast(attrs, [:time_of_occurance])
    |> cast_embed(:time_of_occurance, with: &time_of_occurance_changeset/2)
  end

  defp time_of_occurance_changeset(occurance, attrs) do
    occurance
    |> cast(attrs, [:min, :max])
  end
end

which compiles without any problems

If you still have an issue better to share with us a changed version of your code.

1 Like

Yeah, my code compiles properly, but I got this error on POST method:

mutation {
  createNpc(npc: {
    name: "ddd"
    _id: "jnho5756jh567"
    field_diameter: 0
    type: "static"
    choosed: "npc"
    move_type: "aaa"
    has_visible_level: true
    char_pic: "fawfawfawfa"
    settings: {
      time_of_occurance: {
        min: 0
        max: 24
      }
    }
    statistics: {
      level: 5
      health: 100
      attack: 100
      defence: 1
      strength: 1
      dexterity: 1
      inteligence: 1
      jink: 1
      speed: 1
    }
    monologs: [
      {
        _id: "afawfaw",
				content: "ccc"
      }
    ]
  }) {
    id
  }
}

Here is my project repository: https://github.com/RafalKostecki/angotia-catalogs/tree/dev (“dev” branch).
In my postgresql db “settings” field has “json” type.

What error are you getting? You haven’t shown it.

The same from beginnings: (RuntimeError) casting embeds with cast/4 is not supported, use cast_embed/3 instead. I got this when I trying to create new NPC (look post above)

The error seems pretty straightforward. Somewhere in the code you are calling cast instead of cast_embed. Barely looking at the snippet here it seems there is an extra cast for :time_of_occurance

  def settings_changeset(settings, attrs) do
    settings
    |> cast(attrs, [:time_of_occurance])
    |> cast_embed(:time_of_occurance, with: &time_of_occurance_changeset/2)
  end

Just drop it.

2 Likes