Emad Shaaban
Emad Shaaban
AEAsh Elixir
Created by Emad Shaaban on 7/21/2023 in #support
How to insert a record with its nested children?
First, I'd love to thank everyone and especially Zash for the awesome work done in Ash I have a few resources with some relationships between them, for brevity I'll only copy the relevant parts
defmodule Example.Orders.Order do
use Ash.Resource

attributes do
uuid_primary_key :id
attribute :state, :atom, allow_nil?: false
end

relationships do
has_many :lines, Example.Orders.OrderLine
end
end
defmodule Example.Orders.Order do
use Ash.Resource

attributes do
uuid_primary_key :id
attribute :state, :atom, allow_nil?: false
end

relationships do
has_many :lines, Example.Orders.OrderLine
end
end
defmodule Example.Orders.OrderLine do
use Ash.Resource

attributes do
uuid_primary_key :id
attribute :quantity, :decimal, allow_nil?: false
end

relationships do
belongs_to :order, Example.Orders.Order

belongs_to :product, Example.Products.Product do
api Example.Products
allow_nil? false
attribute_writable? true
end
end
end
defmodule Example.Orders.OrderLine do
use Ash.Resource

attributes do
uuid_primary_key :id
attribute :quantity, :decimal, allow_nil?: false
end

relationships do
belongs_to :order, Example.Orders.Order

belongs_to :product, Example.Products.Product do
api Example.Products
allow_nil? false
attribute_writable? true
end
end
end
What I wish to do is to insert an order along with its lines like this
Example.Orders.Order.create!(%{
state: :draft,
lines: [%{
product_id: ...,
quantity: ...
}]
})
Example.Orders.Order.create!(%{
state: :draft,
lines: [%{
product_id: ...,
quantity: ...
}]
})
I could make it using manage_relationship, but it seems to require lines to be sent as an argument to the create action and not as a part of the order itself. I also tried Ash.Resource.Change like this
defmodule Example.Orders.Order.Changes.SetLines do
use Ash.Resource.Change

def change(changeset, _, _) do
lines = Ash.Changeset.get_attribute(changeset, :lines)

changeset
|> Ash.Changeset.manage_relationship(
:lines,
lines,
type: :direct_control
)
end
end
defmodule Example.Orders.Order.Changes.SetLines do
use Ash.Resource.Change

def change(changeset, _, _) do
lines = Ash.Changeset.get_attribute(changeset, :lines)

changeset
|> Ash.Changeset.manage_relationship(
:lines,
lines,
type: :direct_control
)
end
end
elixir And updated the create action in order resource to be like this
create :create do
change Example.Orders.Order.Changes.SetLines
end
create :create do
change Example.Orders.Order.Changes.SetLines
end
but it doesn't work, and it seems that :lines always get removed from changeset before the change code runs. Am I missing something? I don't mind sending lines as an argument to the action in this case, but then what happens with multiple levels of nesting?
6 replies