Many_to_many on email destination

I'm try to create a many to may relationship between a workspace and a user, using user email instead of the user id. But when i try to create the a WorkspaceUser I get an error:
** (Ash.Error.Invalid) Input Invalid

* Invalid value provided for user: cannot provide structs that don't match the destination.
(ash 2.9.21) lib/ash/api/api.ex:2077: Ash.Api.unwrap_or_raise!/3
iex:16: (file)
** (Ash.Error.Invalid) Input Invalid

* Invalid value provided for user: cannot provide structs that don't match the destination.
(ash 2.9.21) lib/ash/api/api.ex:2077: Ash.Api.unwrap_or_raise!/3
iex:16: (file)
The relation in Workspace is
many_to_many :users, User do
api Accounts.Api
through WorkspaceUser
source_attribute :id
source_attribute_on_join_resource :workspace_id
destination_attribute :email
destination_attribute_on_join_resource :email
validate_destination_attribute? false
end
many_to_many :users, User do
api Accounts.Api
through WorkspaceUser
source_attribute :id
source_attribute_on_join_resource :workspace_id
destination_attribute :email
destination_attribute_on_join_resource :email
validate_destination_attribute? false
end

In WorkspaceUser
relationships do
belongs_to :workspace, Workspace do
api Api
primary_key? true
allow_nil? false
# attribute_type :uuid
end

belongs_to :user, User do
api Accounts.Api
primary_key? true
allow_nil? false
# source_attribute :email
# destination_attribute :email
# attribute_type :ci_string
end
end
relationships do
belongs_to :workspace, Workspace do
api Api
primary_key? true
allow_nil? false
# attribute_type :uuid
end

belongs_to :user, User do
api Accounts.Api
primary_key? true
allow_nil? false
# source_attribute :email
# destination_attribute :email
# attribute_type :ci_string
end
end
The action that throw the error is
create :assign do
argument :workspace_id, :uuid do
allow_nil? false
end

argument :email, :ci_string do
allow_nil? false
end

accept [:role, :status]

change manage_relationship(:email, :user, type: :append_and_remove)
change manage_relationship(:workspace_id, :workspace, type: :append_and_remove)
end
create :assign do
argument :workspace_id, :uuid do
allow_nil? false
end

argument :email, :ci_string do
allow_nil? false
end

accept [:role, :status]

change manage_relationship(:email, :user, type: :append_and_remove)
change manage_relationship(:workspace_id, :workspace, type: :append_and_remove)
end
9 Replies
barnabasj
barnabasj•2y ago
is the action on the WorkspaceUser? If so the email/workspace_id are just attributes and you don't need the manage_relationship stuff. Most of the times the argument you would pass to manage_relationship would be a map with the attributes of the related resource. If you wan't to only manage a single attribute you would need to specify :value_is_key in the opts
barnabasj
barnabasj•2y ago
Ash HQ
Module: Ash.Changeset
View the documentation for Ash.Changeset on Ash HQ.
barnabasj
barnabasj•2y ago
if the action is ment to create a new user you would do somthing like this
create :assign do
argument :workspace_id, :uuid do
allow_nil? false
end

accept [:role, :status, :email]

change manage_relationship(:workspace_id, :workspaces, type: :append_and_remove, value_is_key: :id)
end
create :assign do
argument :workspace_id, :uuid do
allow_nil? false
end

accept [:role, :status, :email]

change manage_relationship(:workspace_id, :workspaces, type: :append_and_remove, value_is_key: :id)
end
and you would also have the relationship declared on the user same as the workspace
many_to_many :workspaces, Workspace do
api Workspace.Api
through WorkspaceUser
source_attribute :email
source_attribute_on_join_resource :email
destination_attribute :id
destination_attribute_on_join_resource :workspace_id
validate_destination_attribute? false
end
many_to_many :workspaces, Workspace do
api Workspace.Api
through WorkspaceUser
source_attribute :email
source_attribute_on_join_resource :email
destination_attribute :id
destination_attribute_on_join_resource :workspace_id
validate_destination_attribute? false
end
ZachDaniel
ZachDaniel•2y ago
That sounds like the correct approach to me 🙂
Bananoid
BananoidOP•2y ago
Thank you very much. I changed the assign action and add the relation to user but I'm still get this error:
** (Ash.Error.Invalid) Input Invalid

* relationship user is required
(ash 2.11.2) lib/ash/api/api.ex:2123: Ash.Api.unwrap_or_raise!/3
iex:7: (file)
** (Ash.Error.Invalid) Input Invalid

* relationship user is required
(ash 2.11.2) lib/ash/api/api.ex:2123: Ash.Api.unwrap_or_raise!/3
iex:7: (file)
I'm trying to use email instead of user id so that I can invite users to the workspace even if they are not yet registered. Is this the right approach to achieve this?
ZachDaniel
ZachDaniel•2y ago
Hard to say really. You might want to go about it by creating an invitations resource and then hooking into the registration logic to add a user to any workspaces they have an invitation for What I might suggest is to roll your own behavior in this instance instead of using manage_relationship because then you can do something like lookup the user by email and if they exist add them to the workspace, and if they don't create an invite for that email address connected to that workspace
Bananoid
BananoidOP•2y ago
Thanks i will try that path. But do you know why I'm getting this error? and if i do
create :assign do
argument :workspace_id, :uuid do
allow_nil? false
end

argument :email, :ci_string do
allow_nil? false
end

accept [:role, :status]

change manage_relationship(
:workspace_id,
:workspace,
type: :append_and_remove,
value_is_key: :id
)

change manage_relationship(
:email,
:user,
type: :append_and_remove,
value_is_key: :email
)
end
create :assign do
argument :workspace_id, :uuid do
allow_nil? false
end

argument :email, :ci_string do
allow_nil? false
end

accept [:role, :status]

change manage_relationship(
:workspace_id,
:workspace,
type: :append_and_remove,
value_is_key: :id
)

change manage_relationship(
:email,
:user,
type: :append_and_remove,
value_is_key: :email
)
end
i get
** (Ash.Error.Invalid) Input Invalid

* Invalid value provided for user: cannot provide structs that don't match the destination.
(ash 2.11.2) lib/ash/api/api.ex:2123: Ash.Api.unwrap_or_raise!/3
iex:7: (file)
** (Ash.Error.Invalid) Input Invalid

* Invalid value provided for user: cannot provide structs that don't match the destination.
(ash 2.11.2) lib/ash/api/api.ex:2123: Ash.Api.unwrap_or_raise!/3
iex:7: (file)
barnabasj
barnabasj•2y ago
Because the argument you specify is passed to the related resources appropriate action e.g. create. And you always need to pass a Params map when calling e.g. Ash.Changset.for_create(:create, %{}=argument, opts) You need to specify the relationships on the resource.
Bananoid
BananoidOP•2y ago
thanks

Did you find this page helpful?