Zagnieżdżone formularze

Witam,

posiadam taki oto model:

Candidate posiada Test, a Test posiada wiele Question.

Model CandidateQuestion miesza id Candidate i Question oraz posiada dodatkowe pole answer. Chciałbym zrobić tak, że wyświetla mi się Test, czyli np 3 Question które posiada i pod każdym jest odpowiedź (answer) po kliknięciu ‘Zakończ test’ wysłało wszystko razem.

No i nie bardzo mogę sobie z tym poradzić :frowning:

W czym dokładnie jest problem? Jeśli chodzi o generowanie formularzy to polecam simple_form + cocoon. Nie testowałem czy dla tego konkretnego przypadku występują jakieś większe problemy. Jeśli tak to napisz, postaram się pomóc.

No własnie chodzi o to że nie bardzo wiem jak się w ogóle za to zabrać. Jak robiłem formularz dla Test to sobie poradziłem. A teraz chodzi o to że chcę wyświetlić ten Test który ma przypisane n Pytań, a do każdego pytania mieć miejsce na odpowiedź, która ma się zapisywać w modelu CandidateQuestion wraz z question_id i candidate_id

jak chcesz mieć relacje z n rzeczami, to albo idziesz w kierunku nested attributes, albo luknij w gem reform.

Wydaje mi się że wystarczy jeśli po prostu przygotujesz odpowiedni widok który będzie wypisywał formularz dla Test z pytaniami (to będzie dosyć prosta pętla wypisująca wszystkie pytania które są powiązane z aktualnie wybranym Testem). Następnie dla każdego pytania wyświetlasz np. input z etykietą taką jak pytanie, a wpisaną w tym input wartość traktujesz jako odpowiedź. Potem musisz tylko napisać metodę odbierającą dane wpisane do tego formularza (tutaj ważne żeby ustawić odpowiednie permitted_params). candidate_id oraz question_id zrobiłbym jako ukryte pola przesyłane wraz z formularzem.

Tutaj jest fajny artykuł jak budować zagnieżdzone formularze używając accept_nested_attributes_for. Jednak w miarę skomplikowania formularza prędzej czy później FormObjects będzie niezastąpiony.

A czy mógł byś podać przykład takiej metody ? :slight_smile:

Tak jak napisał lucas użyj accept_nested_attributes_for, a następnie zezwól na odbieranie wszystkich zagnieżdżonych danych.

Modele

Candidate
has_many candidate_questions
belongs_to test

CandidateQuestion
belongs_to candidate
belongs_to question

Question
has_many candidate_questions
belongs_to test

Test
has_many questions
has_many candidates

W kontrolerze CandidatesController

def new
  @test = Test.where(candidate_id: @candidate.id).first
end

def create
  @candidate = Candidate.new(candidate_params)
  if @candidate.save
  ...
end

private

  def candidate_params
    params.require(:candidate).permit(
      candidate_questions_attributes: [
        candidate_id,
        question_id,
        answer,
      ]
    )
  end

W widoku tworzysz formularz testu dla kandydata na bazie istniejących pytań.

= simple_form_for @candidate do |f|
  = f.simple_fields_for :candidate_questions, @test.questions do |q|
    = f.input :question_id, as: hidden, value: q.id
    = f.input :candidate_id, as: hidden, value: @candidate.id
    = f.input :answer, label: q.question

Wydaje mi się że w ten sposób uzyskasz mniej więcej to co chciałeś.
Mam tylko wątpliwości co do wyświetlania fields_for ale to prostu sprawdź u siebie w aplikacji czy jest ok.

tylko że ja już mam stworzonego kandydata …

W takim razie zamiast w create możesz umieścić formularz dla edycji klienta i wtedy odebrać dane w metodzie update.