У меня двойная вложенная форма, и мне нужно сохранить ID одного из родителей в записи о ребенке. Однако родительская запись может еще не иметь идентификатора, поэтому я не могу сохранить этот идентификатор. Как я могу передать этот ссылочный идентификатор? Спасибо!
Контекст
Я немного новичок в Rails и работаю над приложением домашней работы, где учитель может создать Work
. Work
может иметь Questions
, а Question
- Answers
.
За Work
студент может создать Submission
. Submission
может иметь Answers
(что является ответом на вопросы Work
.
Цель В конечном счете, я хотел бы отобразить информацию для представления учащегося, включая соответствующую Work
информацию, Answers
предоставленную учащимся вместе с Question
, на который они отвечали.
В настоящее время я не могу создать Answer
и указать в нем идентификатор Question
, в который он вложен (что имеет смысл для меня, поскольку при отправке формы Question
может не существовать и выиграть) у меня нет идентификатора.
Мои вопросы:
- Как я могу передать родителя / ссылку
question_id
в answer
?
- Если это невозможно, как я могу реорганизовать эти модели, чтобы я смог достичь поставленной цели?
- Является ли полиморфизм лучшим вариантом здесь, или я должен использовать ИППП? (Или это не относится к моему делу)
код
Мои модели:
модель / work.rb
class Work < ApplicationRecord
has_many :submissions
has_many :questions # Allow for quizzes
accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
end
# == Schema Information
#
# Table name: works
#
# id :bigint(8) not null, primary key
# description :text
# due_date :datetime
# name :string
# submittable :boolean default(TRUE)
# url :string
# created_at :datetime not null
# updated_at :datetime not null
# course_id :integer
#
модель / submission.rb
class Submission < ApplicationRecord
belongs_to :work
has_many :answers, as: :answerable
accepts_nested_attributes_for :answers, reject_if: :all_blank, allow_destroy: true
end
# == Schema Information
#
# Table name: submissions
#
# id :bigint(8) not null, primary key
# enrollment_id :integer
# work_id :integer
# title :string
# content :text
# created_at :datetime not null
# updated_at :datetime not null
#
Модели / question.rb
class Question < ApplicationRecord
belongs_to :work
has_many :answers, as: :answerable
# has_many :answers, as: :answerable, inverse_of: :question
accepts_nested_attributes_for :answers, reject_if: :all_blank, allow_destroy: true
validates :value, presence: true, allow_nil: false
end
# == Schema Information
#
# Table name: questions
#
# id :bigint(8) not null, primary key
# value :string
# created_at :datetime not null
# updated_at :datetime not null
# work_id :bigint(8)
#
# Indexes
#
# index_questions_on_work_id (work_id)
#
модель / answer.rb
class Answer < ApplicationRecord
belongs_to :answerable, polymorphic: true
validates :value, presence: true, allow_nil: false
end
# == Schema Information
#
# Table name: answers
#
# id :bigint(8) not null, primary key
# answerable_type :string
# is_canon :boolean default(FALSE)
# is_correct :boolean default(FALSE)
# value :string
# created_at :datetime not null
# updated_at :datetime not null
# answerable_id :bigint(8)
# question_id :bigint(8)
#
# Indexes
#
# index_answers_on_answerable_id (answerable_id)
# index_answers_on_question_id (question_id)
#
# Foreign Keys
#
# fk_rails_... (question_id => questions.id)
#
Контроллер
* +1058 * Контроллер / works_controller.rb
class WorksController < ApplicationController
def create
@work = Work.new(work_params)
respond_to do |format|
if @work.save
format.html { redirect_to @work, notice: 'Work was successfully created.' }
format.json { render :show, status: :created, location: @work }
else
format.html { render :new }
format.json { render json: @work.errors, status: :unprocessable_entity }
end
end
end
private
def work_params
params.require(:work).permit(:name, :category_id, :course_id, :description, :url, :due_date, :published, :points, :grades_published,
questions_attributes: [:id, :value, :_destroy,
answers_attributes: [:id, :value, :question_id, :is_correct, :is_canon, :_destroy]
]
)
end
end
Просмотров: 1062 * *
_form.html.slim
...
/ Questions
.form-group.u-mt2x
= form.fields_for :questions do |question|
= render 'shared/question_fields', f: question
.links
= link_to_add_association 'Add Question', form, :questions, class: "u-button--New u-button--sm", partial: 'shared/question_fields'
_question_fields.html.slim
.nested-fields
.form-group
.form-group
= f.label :value, "Question", :class => "required"
= link_to_remove_association "remove question", f, data: {confirm: 'Are you sure you want to remove this question?'}
= f.text_field :value, class: "form-control"
// Answers / Choices
.form-group.u-mt2x
= f.fields_for :answers do |answer|
= render 'shared/answer_fields', f: answer
.links
= link_to_add_association 'Add Choice', f, :answers, partial: "shared/answer_fields"
_answer_fields.html.slim
.nested-fields
.form-group
.form-group
= f.label :value, "Answer Choice", :class => "required"
= link_to_remove_association "remove choice", f, data: {confirm: 'Are you sure you want to remove this answer?'}
= f.text_field :value, class: "form-control"
.form-group
= f.label :is_correct, "This is the correct answer"
div
= f.label :is_correct, "Yes", value: true
= f.radio_button :is_correct, true
= f.label :is_correct, "No", value: false
= f.radio_button :is_correct, false
/= f.select :is_correct, options_for_select([["Yes", true], ["No", false]])
// Hidden fields
.form-group
- if current_user.id == @work.course.owner.id
= f.label :is_canon, "Canonical Choice"
= f.hidden_field :is_canon, value: current_user.id == @work.course.owner.id, :readonly => true
/.form-group
- if current_user.id == @work.course.owner.id
= f.label :question_id, "Question ID"
= f.text_field :question_id, @question.id
routes.rb
Rails.application.routes.draw do
resources :submissions
...
devise_for :users, :path => 'auth', :controllers => {:registrations => "registrations"}
get "works/index"
resources :works do
member do
put 'toggle_publish'
put 'toggle_publish_grades'
end
end
...
root 'home#index'
end
Что я пробовал / считал
Добавление inverse_of
к модели Question
дает мне ArgumentError (When assigning attributes, you must pass a hash as an argument.)
Кроме того, кажется, что inverse_of
не очень хорошо работает с polymorphic
отношениями модели.
class Question < ApplicationRecord
...
has_many :answers, as: :answerable, inverse_of: :question
...
end
Я также рассмотрел возможность выделения формы таким образом, чтобы Question
/ Answer
создавались не при отправке формы, а скорее как запрос AJAX, чтобы я мог получить question_id
.
При отправке формы звоните questions_controller
(что вызывает answers_controller
), и каждый из них создает свои собственные записи, а не создает все в пределах works_controller
TLDR
У меня двойная вложенная форма, и мне нужно сохранить ID одного из родителей в записи о ребенке. Однако родительская запись может еще не иметь идентификатора, поэтому я не могу сохранить этот идентификатор. Как я могу передать этот ссылочный идентификатор? Спасибо!