# Terminal bundle add hotwire-rails rails hotwire:set up rails g scaffold questionnaire identify rails g mannequin query questionnaire:belongs_to identify question_type:integer required:boolean rails g mannequin reply query:belongs_to identify
# fashions/questionnaire.rb class Questionnaire < ApplicationRecord has_many :questions, dependent: :destroy accepts_nested_attributes_for :questions, allow_destroy: true finish
# fashions/query.rb class Query < ApplicationRecord belongs_to :questionnaire has_many :solutions, dependent: :destroy accepts_nested_attributes_for :solutions, allow_destroy: true enum question_type: { single_choice: 0, multiple_choice: 1, long_answer: 2 } def self.question_type_select question_types.keys.map okay finish finish
# fashions/reply.rb class Reply < ApplicationRecord belongs_to :query finish
# app/property/javascripts/controllers/nested_form_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = ["add_item", "template"] add_association(occasion) { occasion.preventDefault() var content material = this.templateTarget.innerHTML.change(/TEMPLATE_RECORD/g, new Date().getTime()) this.add_itemTarget.insertAdjacentHTML('beforebegin', content material) } remove_association(occasion) { occasion.preventDefault() let merchandise = occasion.goal.closest(".nested-fields") merchandise.querySelector("enter[name*='_destroy']").worth = 1 merchandise.fashion.show = 'none' } }
# views/questionnaires/_form.html.erb <%= form_with(mannequin: questionnaire) do |type| %> <div class="subject"> <%= type.label :identify %> <%= type.text_field :identify %> </div> <div data-controller="nested-form"> <template data-nested-form-target="template"> <%= type.fields_for :questions, Query.new, child_index: 'TEMPLATE_RECORD' do |query| %> <%= render 'question_fields', type: query %> <% finish %> </template> <%= type.fields_for :questions do |query| %> <%= render 'question_fields', type: query %> <% finish %> <div data-nested-form-target="add_item"> <%= link_to "Add Query", "#", information: { motion: "nested-form#add_association" } %> </div> </div> <div class="actions"> <%= type.submit %> </div> <% finish %>
# views/questionnaires/_question_fields.html.erb <div class="nested-fields field" data-controller="dynamic-select"> <div class="form-group"> <%= type.choose :question_type, options_for_select(Query.question_type_select, chosen: type.object.question_type), {}, 'data-dynamic-select-target': 'choose', 'data-action': 'dynamic-select#chosen' %> </div> <div class="form-group"> <%= type.hidden_field :_destroy %> <%= type.text_field :identify, placeholder: 'Query', class: 'form-control' %> <small> <%= link_to "Take away", "#", information: { motion: "click->nested-form#remove_association" } %> </small> </div> <div data-controller="nested-form" data-dynamic-select-target="alternative"> <template data-nested-form-target="template"> <%= type.fields_for :solutions, Reply.new, child_index: 'TEMPLATE_RECORD' do |reply| %> <%= render 'answer_fields', type: reply %> <% finish %> </template> <%= type.fields_for :solutions do |reply| %> <%= render 'answer_fields', type: reply %> <% finish %> <div data-nested-form-target="add_item"> <%= link_to "Add Reply", "#", information: { motion: "nested-form#add_association" } %> </div> </div> <div data-controller="nested-form" data-dynamic-select-target="lengthy"> </div> </div>
# questionnaire_controller.rb def questionnaire_params params.require(:questionnaire).allow( :identify, questions_attributes: [ :_destroy, :id, :question_type, :name, answers_attributes: [:_destroy, :id, :name] ] ) finish
# views/questionnaires/_answer_fields.html.erb <div class="nested-fields"> <div class="form-group"> <%= type.hidden_field :_destroy %> <%= type.text_field :identify, placeholder: 'Reply', class: 'form-control' %> <small> <%= link_to "Take away Reply", "#", information: { motion: "click->nested-form#remove_association" } %> </small> </div> </div>
# app/property/javascripts/controllers/dynamic_select_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = ["select", "choice", "long"] join() { this.chosen() } chosen() { this.hideFields() swap (this.selectTarget.worth) { case 'single_choice': this.choiceTarget.classList.take away('hidden') break; case 'multiple_choice': this.choiceTarget.classList.take away('hidden') break; case 'long_answer': this.longTarget.classList.take away('hidden') break; } } hideFields() { this.choiceTarget.classList.add('hidden') this.longTarget.classList.add('hidden') } }
# views/questionnaires/present.html.erb <h1><%= @questionnaire.identify %></h1> <% @questionnaire.questions.every do |query| %> <h2><%= query.identify %></h2> <% case query.question_type %> <% when 'single_choice' %> <% query.solutions.every do |reply| %> <p> <%= radio_button_tag query.id, reply.id %> <%= reply.identify %> </p> <% finish %> <% when 'multiple_choice' %> <% query.solutions.every do |reply| %> <p> <%= check_box_tag query.id, reply.id %> <%= reply.identify %> </p> <% finish %> <% when 'long_answer' %> <%= text_area_tag query.id %> <% finish %> <% finish %>