TwistingTwists
Managing many to many relationships
I have a quiz. and a question.
and relation is.
quiz many_to_many question
question many_to_many quiz
via quiz_question
Now, I want to have an api where I can write Quiz.update_quiz_with_question_ids(existing_quiz,[ qid_1,qid_2,qid_3]) which ends up relating question_ids and quiz_ids.
What I tried:
update :update_quiz_with_question_ids do
accept []
argument :question_ids, {:array, :uuid} do
allow_nil? false
end
change manage_relationship(:questions, :question_ids, type: :direct_control)
end
which leaves with the following error
{:error,
%Ash.Error.Invalid{
errors: [
%Ash.Error.Query.Required{
field: :question_id,
type: :argument,
resource: PyqRatta.Databank.Question,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :invalid
}
],
...
So, I tried a little differently.
update :update_quiz_with_question_ids do
accept []
argument :question_ids, {:array, :uuid} do
allow_nil? false
end
change manage_relationship(:questions, :question_ids,
on_match: :ignore,
on_lookup: :relate,
on_no_match: :relate,
# since we are adding more questions to the quiz.
on_missing: :ignore)
end
and same error persists. Finally, did one more tweak.
defmodule Databank.Changes.QuestionsFromQuestionIds do
@moduledoc """
Fetches questions from database to udpate the relationship from questions to quizzes
"""
use Ash.Resource.Change
alias Databank.Quiz
alias Databank.Question
alias Databank.QuizQuestion
def change(changeset, opts, context) do
quiz_id = Ash.Changeset.get_data(changeset, :id)
qids = Ash.Changeset.get_argument(changeset, :question_ids)
questions =
Enum.reduce(qids, [], fn qid, acc ->
{:ok, question} = Question.read(qid)
acc ++ [question]
end)
Ash.Changeset.force_set_argument(changeset, :question_ids, questions)
end
end
along with
update :update_quiz_with_question_ids do
accept []
argument :question_ids, {:array, :uuid} do
allow_nil? false
end
change Databank.Changes.QuestionsFromQuestionIds
change manage_relationship(:question_ids, :questions, type: :direct_control)
end
the changeset is :
#Ash.Changeset<
api: Databank,
action_type: :update,
action: :update_quiz_with_question_id,
attributes: %{},
relationships: %{
questions: [
{[%{id: "39f41254-f959-4f1d-96d4-30500d96d8d1"}],
[
ignore?: false,
on_missing: :destroy,
on_match: :update,
on_lookup: :ignore,
on_no_match: :create,
eager_validate_with: false,
authorize?: true,
meta: [inputs_was_list?: false, id: :question_id],
type: :direct_control
]}
]
},
arguments: %{question_id: "39f41254-f959-4f1d-96d4-30500d96d8d1"},
errors: [
%Ash.Error.Invalid{
errors: [
%Ash.Error.Query.Required{
field: :question_id,
type: :argument,
resource: Databank.Question,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :invalid
}
],
stacktraces?: true,
changeset: nil,
query: #Ash.Query<
resource: Databank.Quiz,
load: [questions: []],
errors: [
%Ash.Error.Invalid{
errors: [
%Ash.Error.Query.Required{
field: :question_id,
type: :argument,
resource: Databank.Question,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :invalid
}
],
stacktraces?: true,
changeset: nil,
query: #Ash.Query<
resource: Databank.Question,
filter: #Ash.Filter<id == nil>,
errors: [
%Ash.Error.Query.Required{
field: :question_id,
type: :argument,
resource: Databank.Question,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :invalid
}
],
select: [:id, :question_text, :question_image, :type,
:correct_answer_text, :correct_answer_image,
:explanation_text, :explanation_image, :short_description,
:long_description, :year, :tags, :created_at, :updated_at]
>,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :invalid
},
%Ash.Error.Query.Required{
field: :question_id,
type: :argument,
resource: Databank.Question,
changeset: nil,
query: nil,
error_context: [],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :invalid
}
]
>,
error_context: [nil],
vars: [],
path: [],
stacktrace: #Stacktrace<>,
class: :invalid
},
...
The reasoning behind this is : if manage_relationship can alter the fields via given relationship key. But that doesn’t appear to be the case for many to many
TL;DR
create an Api where
relation is.
quiz many_to_many question
question many_to_many quiz
via quiz_question
Quiz.update_quiz_with_question_ids(existing_quiz,[ qid_1,qid_2,qid_3]) which ends up relating question_ids and quiz_ids.
Marked As Solved
zachdaniel
Ah, never mind, you do ![]()
This is the issue:
read :read do
argument :question_id, :uuid do
allow_nil? false
end
# to indicate that only one record will be returned
get? true
primary? true
filter expr(id == ^arg(:question_id))
end
Your primary read action should not have required arguments. If it does, anything that tries to use it (like manage_relationship won’t know what to supply as the argument value.
Also Liked
TwistingTwists
Last Post!
TwistingTwists
Popular in Questions
Other popular topics
Latest Ash Threads
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #hex
- #security









