Ash FrameworkAF
Ash Frameworkโ€ข3y agoโ€ข
5 replies
Emad Shaaban

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.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: ...
  }]
})


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
elixir

And updated the create action in order resource to be like this

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?
Was this page helpful?