Many to Many Error

Given these relationships:
# Capability
relationships do
many_to_many :steps, Hsm.Ash.MCP.Step do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :capability_id
destination_attribute_on_join_resource :step_id
end
end

# Step
relationships do
many_to_many :capabilities, Hsm.Ash.Workcenters.Capability do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :step_id
destination_attribute_on_join_resource :capability_id
end
end

# StepCapability
relationships do
belongs_to :capability, Hsm.Ash.Workcenters.Capability,
allow_nil?: false,
api: Hsm.Ash.Workcenters
belongs_to :step, Hsm.Ash.MCP.Step, allow_nil?: false, api: Hsm.Ash.MCP
end
# Capability
relationships do
many_to_many :steps, Hsm.Ash.MCP.Step do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :capability_id
destination_attribute_on_join_resource :step_id
end
end

# Step
relationships do
many_to_many :capabilities, Hsm.Ash.Workcenters.Capability do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :step_id
destination_attribute_on_join_resource :capability_id
end
end

# StepCapability
relationships do
belongs_to :capability, Hsm.Ash.Workcenters.Capability,
allow_nil?: false,
api: Hsm.Ash.Workcenters
belongs_to :step, Hsm.Ash.MCP.Step, allow_nil?: false, api: Hsm.Ash.MCP
end
All of them are in the same API and Registry. I'm getting an error that I don't quite understand (join_relationship_name???):
** (EXIT from #PID<0.96.0>) an exception was raised:
** (RuntimeError) Resource `Hsm.Ash.MCP.StepCapability` is not in registry `Hsm.Ash.Workcenters.Registry` for autogenerated join relationship: `:steps_join_assoc`

Relationship was generated by the `many_to_many` relationship `:steps`

If the `through` resource `Hsm.Ash.MCP.StepCapability` is not accepted by the same
api as the destination resource `Hsm.Ash.MCP.Step`,
then you must define that relationship manually. To define it manually, add the following to your
relationships:

has_many :steps_join_assoc, Hsm.Ash.MCP.StepCapability do
# configure the relationship attributes
...
end

You can use a name other than `:steps_join_assoc`, but if you do, make sure to
add that to `:steps`, i.e

many_to_many :steps_join_assoc, Hsm.Ash.MCP.StepCapability do
...
join_relationship_name :your_new_name
end

(ash 2.9.5) lib/ash/registry/extensions/resource_validations/verifiers/validate_related_resource_inclusion.ex:43: anonymous fn/5 in Ash.Registry.ResourceValidations.Verifiers.ValidateRelatedResourceInclusion.verify/1
(elixir 1.14.4) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.9.5) lib/ash/registry/extensions/resource_validations/verifiers/validate_related_resource_inclusion.ex:16: anonymous fn/4 in Ash.Registry.ResourceValidations.Verifiers.ValidateRelatedResourceInclusion.verify/1
(elixir 1.14.4) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.9.5) lib/ash/registry/extensions/resource_validations/verifiers/validate_related_resource_inclusion.ex:15: Ash.Registry.ResourceValidations.Verifiers.ValidateRelatedResourceInclusion.verify/1
lib/hsm/ash/workcenters/registry.ex:1: anonymous fn/1 in Hsm.Ash.Workcenters.Registry.__verify_ash_dsl__/1
(elixir 1.14.4) lib/enum.ex:975: Enum."-each/2-lists^foreach/1-0-"/2
lib/hsm/ash/workcenters/registry.ex:1: Hsm.Ash.Workcenters.Registry.__verify_ash_dsl__/1
** (EXIT from #PID<0.96.0>) an exception was raised:
** (RuntimeError) Resource `Hsm.Ash.MCP.StepCapability` is not in registry `Hsm.Ash.Workcenters.Registry` for autogenerated join relationship: `:steps_join_assoc`

Relationship was generated by the `many_to_many` relationship `:steps`

If the `through` resource `Hsm.Ash.MCP.StepCapability` is not accepted by the same
api as the destination resource `Hsm.Ash.MCP.Step`,
then you must define that relationship manually. To define it manually, add the following to your
relationships:

has_many :steps_join_assoc, Hsm.Ash.MCP.StepCapability do
# configure the relationship attributes
...
end

You can use a name other than `:steps_join_assoc`, but if you do, make sure to
add that to `:steps`, i.e

many_to_many :steps_join_assoc, Hsm.Ash.MCP.StepCapability do
...
join_relationship_name :your_new_name
end

(ash 2.9.5) lib/ash/registry/extensions/resource_validations/verifiers/validate_related_resource_inclusion.ex:43: anonymous fn/5 in Ash.Registry.ResourceValidations.Verifiers.ValidateRelatedResourceInclusion.verify/1
(elixir 1.14.4) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.9.5) lib/ash/registry/extensions/resource_validations/verifiers/validate_related_resource_inclusion.ex:16: anonymous fn/4 in Ash.Registry.ResourceValidations.Verifiers.ValidateRelatedResourceInclusion.verify/1
(elixir 1.14.4) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.9.5) lib/ash/registry/extensions/resource_validations/verifiers/validate_related_resource_inclusion.ex:15: Ash.Registry.ResourceValidations.Verifiers.ValidateRelatedResourceInclusion.verify/1
lib/hsm/ash/workcenters/registry.ex:1: anonymous fn/1 in Hsm.Ash.Workcenters.Registry.__verify_ash_dsl__/1
(elixir 1.14.4) lib/enum.ex:975: Enum."-each/2-lists^foreach/1-0-"/2
lib/hsm/ash/workcenters/registry.ex:1: Hsm.Ash.Workcenters.Registry.__verify_ash_dsl__/1
I'm probably missing something obvious, but I can't spot it.
15 Replies
TechnoMage
TechnoMage3y ago
I have not gotten many to many to work quite yet, but mine at lest compile. I suggest looking for references or imports or aliases of Hsm.Ash.MCP.StepCapability given it is in the error and not appearly what you are expecting to be involved.
frankdugan3
frankdugan3OP3y ago
Yeah, pasted the wrong defs. I don't use aliases to avoid those kinds of problems. Post edited w/ correct definitions. ^ Oh, is this as simple as needing to add it to both registries? :thinkies:
TechnoMage
TechnoMage3y ago
It is making up the resource name 'steps_join_assoc' for some reason. It looks like you have through specified, I would double check that the join resource is in the same API and registry as the others.
frankdugan3
frankdugan3OP3y ago
The join resource is in the MCP registry/api, not Workcenters. I'm just not clear on how to deal with that, as specifying the api on either/both many_to_many still produces the same error. It's also not clear in the docs if the api option in a many_to_many is supposed to point to the API of t he destination resource or the join resource.
TechnoMage
TechnoMage3y ago
The docs state that the API option is for the destination resource. Looks like it is a missing option. I would file an issue, and in the mean time add the join resource to both API and Registries.
frankdugan3
frankdugan3OP3y ago
The docs say "related entity" for the api on a many_to_many, which to me is not clearly indicating "destination", which is the term it consistently uses. I mean, that's probably what it means, but it's unclear IMO. Yeah, I'm consistently doing something wrong w/ my cross-api many-to-many relationships because they all have this problem. @Zach Daniel When you get a chance, could use some guidance. (no rush) 😵‍💫 OK, I think the solution was a few steps: 1) add the api options to all the many-to-many relationships, 2) add the join resource to both api/registries and 3) make sure the join resource specifies the API for each relationship. Need to do this to the rest of them to make sure.
ZachDaniel
ZachDaniel3y ago
You shouldn’t need to add the join resource to both apis *registries The idea of the warning is that if you set the api of a many to many relationship, and we generate a has_many for it, we assume that the through resource is in the destination api. If it’s not, then you need to define the underlying has_many yourself and not set an api (or set it to the correct api) And then use that with join_relationship And the api in a many to many should point to the destination resource api.
frankdugan3
frankdugan3OP3y ago
Might be a bug then, because given this:
# Step (MCP API)
many_to_many :capabilities, Hsm.Ash.Workcenters.Capability do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :step_id
destination_attribute_on_join_resource :capability_id
api Hsm.Ash.Workcenters
end

# Capability (Workcenters API)
many_to_many :mcp_steps, Hsm.Ash.MCP.Step do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :capability_id
destination_attribute_on_join_resource :step_id
api Hsm.Ash.MCP
end

# StepCapability (MCP API)
relationships do
belongs_to :capability, Hsm.Ash.Workcenters.Capability,
allow_nil?: false,
api: Hsm.Ash.Workcenters

belongs_to :step, Hsm.Ash.MCP.Step, allow_nil?: false, api: Hsm.Ash.MCP
end
# Step (MCP API)
many_to_many :capabilities, Hsm.Ash.Workcenters.Capability do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :step_id
destination_attribute_on_join_resource :capability_id
api Hsm.Ash.Workcenters
end

# Capability (Workcenters API)
many_to_many :mcp_steps, Hsm.Ash.MCP.Step do
through Hsm.Ash.MCP.StepCapability
source_attribute_on_join_resource :capability_id
destination_attribute_on_join_resource :step_id
api Hsm.Ash.MCP
end

# StepCapability (MCP API)
relationships do
belongs_to :capability, Hsm.Ash.Workcenters.Capability,
allow_nil?: false,
api: Hsm.Ash.Workcenters

belongs_to :step, Hsm.Ash.MCP.Step, allow_nil?: false, api: Hsm.Ash.MCP
end
Hsm.Ash.MCP.StepCapability is added to the MCP registry, but will still give the compile error unless I also add it to the Workcenters registry. :thinkies:
ZachDaniel
ZachDaniel3y ago
Well, the through resource is only in one of them So you will always get an error unless you manually define the underlying has_many relationship for one of them not specifying the api for that one (I.e the through resource is in my api not theirs) If you define two many to many relationships across an api boundary without doing that, one of them will always error unless the through resource is in both.
frankdugan3
frankdugan3OP3y ago
Ahh... OK. Is there any harm to just including the through relationship in both registries to avoid the manual has_many? Just trying to figure out best practice, will PR some of these details in the guides/docs.
ZachDaniel
ZachDaniel3y ago
No harm really, no. But I’d suggest just picking which api it belongs in and on one end define the has_many for the many_to_many
rohan
rohan2y ago
came up against this now, it doesn't seem to be documented in the relationship docs anywhere actually I'm really confused by what I'm supposed to do here. I'm getting:
an exception was raised:
** (RuntimeError) Resource `Scribble.Scribe.UserMedicalTerm` is not accepted by api `Scribble.EmailHandler` for autogenerated join relationship: `:users_join_assoc`

Relationship was generated by the `many_to_many` relationship `:users`

If the `through` resource `Scribble.Scribe.UserMedicalTerm` is not accepted by the same
api as the destination resource `Scribble.EmailHandler.User`,
then you must define that relationship manually. To define it manually, add the following to your
relationships:

has_many :users_join_assoc, Scribble.Scribe.UserMedicalTerm do
# configure the relationship attributes
...
end

You can use a name other than `:users_join_assoc`, but if you do, make sure to
add that to `:users`, i.e

many_to_many :users_join_assoc, Scribble.Scribe.UserMedicalTerm do
...
join_relationship_name :your_new_name
end
an exception was raised:
** (RuntimeError) Resource `Scribble.Scribe.UserMedicalTerm` is not accepted by api `Scribble.EmailHandler` for autogenerated join relationship: `:users_join_assoc`

Relationship was generated by the `many_to_many` relationship `:users`

If the `through` resource `Scribble.Scribe.UserMedicalTerm` is not accepted by the same
api as the destination resource `Scribble.EmailHandler.User`,
then you must define that relationship manually. To define it manually, add the following to your
relationships:

has_many :users_join_assoc, Scribble.Scribe.UserMedicalTerm do
# configure the relationship attributes
...
end

You can use a name other than `:users_join_assoc`, but if you do, make sure to
add that to `:users`, i.e

many_to_many :users_join_assoc, Scribble.Scribe.UserMedicalTerm do
...
join_relationship_name :your_new_name
end
am I supposed to literally call it :users_join_assoc? I think having an example of this in the docs would be really helpful, right now the docs only says that the api must be defined if many_to_many is crossing api boundaries
ZachDaniel
ZachDaniel2y ago
You can call it whatever you want, but then you need to say join_relationship :relationship_name in your many to many. Agreed an example would be helpful
drumusician
drumusician2y ago
I have a question related to the many_to_many. I have a pretty basic many to many in one Api. Currently I'm seeding some data, but it fails to write the join table when I add the associated data directly in the params. Is this not supported (yet)? In Ecto this would mean adding the cast_assoc for the related items checking out the managing relationships guide as it seems that's where I can configure this
ZachDaniel
ZachDaniel2y ago
Yep 🙂 managing relationships (or custom changes w/ after action hooks) is what you'd want there

Did you find this page helpful?