Ecto.Schema.embeds_many

You're seeing just the macro embeds_many, go back to Ecto.Schema module for more information.
Link to this macro

embeds_many(name, schema, opts \\ [])

View Source (macro)

Indicates an embedding of many schemas.

The current schema has zero or more records of the other schema embedded inside of it. Embeds have all the things regular schemas have.

It is recommended to declare your embeds_many/3 field with type :map in your migrations, instead of using {:array, :map}. Ecto can work with both maps and arrays as the container for embeds (and in most databases map are represented as JSON which allows Ecto to choose what works best).

The embedded may or may not have a primary key. Ecto uses the primary keys to detect if an embed is being updated or not. If a primary is not present and you still want the list of embeds to be updated, :on_replace must be set to :delete, forcing all current embeds to be deleted and replaced by new ones whenever a new list of embeds is set.

For encoding and decoding of embeds, please read the docs for embeds_one/3.

Options

  • :on_replace - The action taken on associations when the embed is replaced when casting or manipulating parent changeset. May be :raise (default), :mark_as_invalid, or :delete. See Ecto.Changeset's section on related data for more info.

  • :source - Defines the name that is to be used in database for this field. This is useful when attaching to an existing database. The value should be an atom.

Examples

defmodule Order do
  use Ecto.Schema

  schema "orders" do
    embeds_many :items, Item
  end
end

defmodule Item do
  use Ecto.Schema

  embedded_schema do
    field :title
  end
end

# The items are loaded with the order
order = Repo.get!(Order, 42)
order.items #=> [%Item{...}, ...]

Adding and removal of embeds can only be done via the Ecto.Changeset API so Ecto can properly track the embed life-cycle:

# Order has no items
order = Repo.get!(Order, 42)
order.items
# => []

items  = [%Item{title: "Soap"}]

# Generate a changeset
changeset = Ecto.Changeset.change(order)

# Put a one or more new items
changeset = Ecto.Changeset.put_embed(changeset, :items, items)

# Update the order and fetch items
items = Repo.update!(changeset).items

# Items are generated with a unique identification
items
# => [%Item{id: "20a97d94-f79b-4e63-a875-85deed7719b7", title: "Soap"}]

Updating of embeds must be done using a changeset for each changed embed.

# Order has an existing items
order = Repo.get!(Order, 42)
order.items
# => [%Item{id: "20a97d94-f79b-4e63-a875-85deed7719b7", title: "Soap"}]

# Generate a changeset
changeset = Ecto.Changeset.change(order)

# Put the updated item as a changeset
current_item = List.first(order.items)
item_changeset = Ecto.Changeset.change(current_item, title: "Mujju's Soap")
order_changeset = Ecto.Changeset.put_embed(changeset, :items, [item_changeset])

# Update the order and fetch items
items = Repo.update!(order_changeset).items

# Item has the updated title
items
# => [%Item{id: "20a97d94-f79b-4e63-a875-85deed7719b7", title: "Mujju's Soap"}]

Inline embedded schema

The schema module can be defined inline in the parent schema in simple cases:

defmodule Parent do
  use Ecto.Schema

  schema "parents" do
    field :name, :string

    embeds_many :children, Child do
      field :name, :string
      field :age,  :integer
    end
  end
end

Primary keys are automatically set up for embedded schemas as well, defaulting to {:id, :binary_id, autogenerate: true}. You can customize it by passing a :primary_key option with the same arguments as @primary_key (see the Schema attributes section for more info).

Defining embedded schema in such a way will define a Parent.Child module with the appropriate struct. In order to properly cast the embedded schema. When casting the inline-defined embedded schemas you need to use the :with option of cast_embed/3 to provide the proper function to do the casting. For example:

def changeset(schema, params) do
  schema
  |> cast(params, [:name])
  |> cast_embed(:children, with: &child_changeset/2)
end

defp child_changeset(schema, params) do
  schema
  |> cast(params, [:name, :age])
end
Link to this macro

embeds_many(name, schema, opts, list)

View Source (macro)

Indicates an embedding of many schemas.

For options and examples see documentation of embeds_many/3.