I have an item
table which I want to have multiple embedded schema
like:
schema "items" do
field :name, :string
field :type, :string
#embed_one with :either, I found this somewhere online but can't get the doc anywhere.
embeds_one :details, either: [ Product, Service], on_replace: :update
@doc false
def changeset(item, attrs) do
item
|> cast(attrs, [:name, :type, :description, :publish, :user_id])
|> details_by_type(attrs[:type], :details)
end
#psuedo code of cast_embed
defp details_by_type(item, type, details) do
case type do
:product -> item |> #cast_embed of :details to Product
:service -> item |> #cast_embed of :details to Service
end
end
Basically, I want to have a details
field(:map) that keep different embedded schema based on the type of the item. But I can't get it to work. I keep getting error like this:
(ArgumentError) you attempted to apply a function on [either: [OkBackend.Items.Task, OkBackend.Items.Product, OkBackend.Items.Service], on_replace: :update]. Modules (the first argument of apply) must always be an atom
What is the right way of doing this?
Looks like this package is what you're looking for, here's an example from the documentation:
defmodule MyApp.Reminder do
use Ecto.Schema
import Ecto.Changeset
import PolymorphicEmbed, only: [cast_polymorphic_embed: 3]
schema "reminders" do
field :date, :utc_datetime
field :text, :string
field :channel, PolymorphicEmbed,
types: [
sms: MyApp.Channel.SMS,
email: [module: MyApp.Channel.Email, identify_by_fields: [:address, :confirmed]]
],
on_type_not_found: :raise,
on_replace: :update
end
def changeset(struct, values) do
struct
|> cast(values, [:date, :text])
|> cast_polymorphic_embed(:channel, required: true)
|> validate_required(:date)
end
end