many_to_many update problem

I have a product which has many_to_many tags. Creating works. Updating doesn't. Here's the resource code: lib/app/shop/resources/product.ex
defmodule App.Shop.Product do
use Ash.Resource, data_layer: Ash.DataLayer.Ets

attributes do
uuid_primary_key :id
attribute :name, :string
attribute :price, :decimal
end

relationships do
many_to_many :tags, App.Shop.Tag do
through App.Shop.ProductTag
source_attribute_on_join_resource :product_id
destination_attribute_on_join_resource :tag_id
end
end

actions do
defaults [:read, :destroy]

create :create do
primary? true
argument :tags, {:array, :map}
change manage_relationship(:tags, type: :append_and_remove, on_no_match: :create)
end

create :update do
argument :tags, {:array, :map}
change manage_relationship(:tags, type: :append_and_remove, on_no_match: :create)
end
end

code_interface do
define_for App.Shop
define :create
define :read
define :by_name, get_by: [:name], action: :read
define :update
define :destroy
end
end
defmodule App.Shop.Product do
use Ash.Resource, data_layer: Ash.DataLayer.Ets

attributes do
uuid_primary_key :id
attribute :name, :string
attribute :price, :decimal
end

relationships do
many_to_many :tags, App.Shop.Tag do
through App.Shop.ProductTag
source_attribute_on_join_resource :product_id
destination_attribute_on_join_resource :tag_id
end
end

actions do
defaults [:read, :destroy]

create :create do
primary? true
argument :tags, {:array, :map}
change manage_relationship(:tags, type: :append_and_remove, on_no_match: :create)
end

create :update do
argument :tags, {:array, :map}
change manage_relationship(:tags, type: :append_and_remove, on_no_match: :create)
end
end

code_interface do
define_for App.Shop
define :create
define :read
define :by_name, get_by: [:name], action: :read
define :update
define :destroy
end
end
Here's what I do in the iex:
iex(1)> good_deal_tag = App.Shop.Tag.create!(%{name: "Good deal"})
iex(2)> yellow_tag = App.Shop.Tag.create!(%{name: "Yellow"})
iex(3)> App.Shop.Product.create!(%{
name: "Banana",
tags: [good_deal_tag, yellow_tag]
})
iex(4) banana = App.Shop.Product.by_name!("Banana", load: [:tags])
iex(1)> good_deal_tag = App.Shop.Tag.create!(%{name: "Good deal"})
iex(2)> yellow_tag = App.Shop.Tag.create!(%{name: "Yellow"})
iex(3)> App.Shop.Product.create!(%{
name: "Banana",
tags: [good_deal_tag, yellow_tag]
})
iex(4) banana = App.Shop.Product.by_name!("Banana", load: [:tags])
That all works nicely. But I can not update the products tags or the even the product:
iex(16)> App.Shop.Product.update!(banana, %{tags: [yellow_tag]})
** (FunctionClauseError) no function clause matching in Keyword.split/2
[...]
iex(16)> App.Shop.Product.update!(banana, %{name: "test"})
** (FunctionClauseError) no function clause matching in Keyword.split/2
iex(16)> App.Shop.Product.update!(banana, %{tags: [yellow_tag]})
** (FunctionClauseError) no function clause matching in Keyword.split/2
[...]
iex(16)> App.Shop.Product.update!(banana, %{name: "test"})
** (FunctionClauseError) no function clause matching in Keyword.split/2
How can I fix this?
6 Replies
Theosaurus
Theosaurus•2y ago
Hey there! I could be totally wrong but I think from memory if something is stated as an argument you have to just pass it as App.Shop.Product.update!(banana, [yellow_tag]) rather than in a struct (I think), and additionally may need to include args: [tags] in your code interface for the update action. Hopefully that helps? I could be totally wrong as I tend to always mix up argument and accepts and the correct syntax for calling them 😅
Stefan Wintermeyer
Stefan WintermeyerOP•2y ago
I tried
iex(5)> App.Shop.Product.update!(banana, [yellow_tag])
** (FunctionClauseError) no function clause matching in anonymous fn/2 in Keyword.split/2
iex(5)> App.Shop.Product.update!(banana, [yellow_tag])
** (FunctionClauseError) no function clause matching in anonymous fn/2 in Keyword.split/2
But I don't know how to do the args: [tags] thing and I am lost in the documentation. @Zach Daniel Can you help me out here? I'd like to record the tutorial.
ZachDaniel
ZachDaniel•2y ago
You’ve defined your action called :update but is a create action So the first argument would be different, causing the error you see We should provide better error there of course But it should work if you change it to an update action I.e create :update
Stefan Wintermeyer
Stefan WintermeyerOP•2y ago
I draw a blank here. The code already says:
create :update do
argument :tags, {:array, :map}
change manage_relationship(:tags, type: :append_and_remove, on_no_match: :create)
end
create :update do
argument :tags, {:array, :map}
change manage_relationship(:tags, type: :append_and_remove, on_no_match: :create)
end
Where would I include an other create?
ZachDaniel
ZachDaniel•2y ago
It should say update :update Not create :update
Stefan Wintermeyer
Stefan WintermeyerOP•2y ago
Ahhh! Thanks! It works.

Did you find this page helpful?