Ecto.Schema.embeds_one
embeds_one
, go back to Ecto.Schema module for more information.
Indicates an embedding of a schema.
The current schema has zero or one records of the other schema embedded
inside of it. It uses a field similar to the :map
type for storage,
but allows embeds to have all the things regular schema can.
You must declare your embeds_one/3
field with type :map
at the
database level.
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 key is not present,
:on_replace
should be set to either :update
or :delete
if there is a
desire to either update or delete the current embed when a new one is set.
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
,:update
, or:delete
. SeeEcto.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_one :item, Item
end
end
defmodule Item do
use Ecto.Schema
embedded_schema do
field :title
end
end
# The item is loaded with the order
order = Repo.get!(Order, 42)
order.item #=> %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 = Repo.get!(Order, 42)
item = %Item{title: "Soap"}
# Generate a changeset
changeset = Ecto.Changeset.change(order)
# Put a new embed to the changeset
changeset = Ecto.Changeset.put_embed(changeset, :item, item)
# Update the order, and fetch the item
item = Repo.update!(changeset).item
# Item is generated with a unique identification
item
# => %Item{id: "20a97d94-f79b-4e63-a875-85deed7719b7", title: "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_one :child, Child do
field :name, :string
field :age, :integer
end
end
end
Options should be passed before the do
block like this:
embeds_one :child, Child, on_replace: :delete do
field :name, :string
field :age, :integer
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 Ecto.Changeset.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(:child, with: &child_changeset/2)
end
defp child_changeset(schema, params) do
schema
|> cast(params, [:name, :age])
end
Encoding and decoding
Because many databases do not support direct encoding and decoding of embeds, it is often emulated by Ecto by using specific encoding and decoding rules.
For example, PostgreSQL will store embeds on top of JSONB columns, which means types in embedded schemas won't go through the usual dump->DB->load cycle but rather encode->DB->decode->cast. This means that, when using embedded schemas with databases like PG or MySQL, make sure all of your types can be JSON encoded/decoded correctly. Ecto provides this guarantee for all built-in types.
Indicates an embedding of a schema.
For options and examples see documentation of embeds_one/3
.