diff --git a/Gemfile b/Gemfile index e0b35b14..880f410f 100644 --- a/Gemfile +++ b/Gemfile @@ -64,6 +64,8 @@ gem "validate_url" # For pausing pipelines gem "aws-sdk-codepipeline", "~> 1.74" +gem "active_model_serializers" + group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem "debug", platforms: %i[mri mingw x64_mingw] diff --git a/Gemfile.lock b/Gemfile.lock index 1c6bb06c..b089e173 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -60,6 +60,11 @@ GEM erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) + active_model_serializers (0.10.14) + actionpack (>= 4.1) + activemodel (>= 4.1) + case_transform (>= 0.2) + jsonapi-renderer (>= 0.1.1.beta1, < 0.3) activejob (7.1.3.4) activesupport (= 7.1.3.4) globalid (>= 0.3.6) @@ -114,6 +119,8 @@ GEM bundler-audit (0.9.1) bundler (>= 1.2.0, < 3) thor (~> 1.0) + case_transform (0.2) + activesupport concurrent-ruby (1.3.1) config (5.5.1) deep_merge (~> 1.2, >= 1.2.1) @@ -145,6 +152,7 @@ GEM reline (>= 0.4.2) jmespath (1.6.2) json (2.7.2) + jsonapi-renderer (0.2.2) language_server-protocol (3.17.0.3) lograge (0.14.0) actionpack (>= 4) @@ -344,6 +352,7 @@ PLATFORMS DEPENDENCIES aasm (~> 5.5) + active_model_serializers acts_as_list after_commit_everywhere (~> 1.4) aws-sdk-codepipeline (~> 1.74) diff --git a/app/models/form.rb b/app/models/form.rb index 8a27db16..afb91582 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -5,6 +5,7 @@ class Form < ApplicationRecord has_many :pages, -> { order(position: :asc) }, dependent: :destroy has_many :made_live_forms, -> { order(created_at: :asc) }, dependent: :destroy + has_many :steps, -> { order(position: :asc) }, dependent: :destroy validates :name, presence: true validates :payment_url, url: true, allow_blank: true diff --git a/app/models/question.rb b/app/models/question.rb new file mode 100644 index 00000000..b77b6a9a --- /dev/null +++ b/app/models/question.rb @@ -0,0 +1,2 @@ +class Question < ApplicationRecord +end diff --git a/app/models/question_set.rb b/app/models/question_set.rb new file mode 100644 index 00000000..62ae23d3 --- /dev/null +++ b/app/models/question_set.rb @@ -0,0 +1,3 @@ +class QuestionSet < ApplicationRecord + has_many :steps, -> { order(position: :asc) }, class_name: "Step", foreign_key: "parent_question_set_id", dependent: :destroy +end diff --git a/app/models/step.rb b/app/models/step.rb new file mode 100644 index 00000000..42c2e9d6 --- /dev/null +++ b/app/models/step.rb @@ -0,0 +1,6 @@ +class Step < ApplicationRecord + belongs_to :positionable, polymorphic: true + belongs_to :next_step, class_name: "Step", optional: true + belongs_to :form, optional: true + belongs_to :parent_question_set, class_name: "QuestionSet", optional: true +end diff --git a/app/serializers/form_snapshot_serializer.rb b/app/serializers/form_snapshot_serializer.rb new file mode 100644 index 00000000..afaa61ec --- /dev/null +++ b/app/serializers/form_snapshot_serializer.rb @@ -0,0 +1,6 @@ +class FormSnapshotSerializer < ActiveModel::Serializer + attributes :id, :name, :submission_email, :privacy_policy_url, :form_slug, :support_email, :support_phone, + :support_url, :support_url_text, :declaration_text, :what_happens_next_markdown, :payment_url, :start_page + + has_many :steps +end diff --git a/app/serializers/question_serializer.rb b/app/serializers/question_serializer.rb new file mode 100644 index 00000000..bef97f54 --- /dev/null +++ b/app/serializers/question_serializer.rb @@ -0,0 +1,3 @@ +class QuestionSerializer < ActiveModel::Serializer + attributes :question_text +end diff --git a/app/serializers/question_set_serializer.rb b/app/serializers/question_set_serializer.rb new file mode 100644 index 00000000..d0d82c39 --- /dev/null +++ b/app/serializers/question_set_serializer.rb @@ -0,0 +1,5 @@ +class QuestionSetSerializer < ActiveModel::Serializer + attributes :name + + has_many :steps +end diff --git a/app/serializers/step_serializer.rb b/app/serializers/step_serializer.rb new file mode 100644 index 00000000..bf4f31f7 --- /dev/null +++ b/app/serializers/step_serializer.rb @@ -0,0 +1,6 @@ +class StepSerializer < ActiveModel::Serializer + attributes :id, :next_step_id, :position, :min_answers, :max_answers + attribute :positionable_type, key: :type + + has_one :positionable, key: :data +end diff --git a/db/migrate/20240618151516_create_questions.rb b/db/migrate/20240618151516_create_questions.rb new file mode 100644 index 00000000..a81b7e04 --- /dev/null +++ b/db/migrate/20240618151516_create_questions.rb @@ -0,0 +1,9 @@ +class CreateQuestions < ActiveRecord::Migration[7.1] + def change + create_table :questions do |t| + t.string :question_text + + t.timestamps + end + end +end diff --git a/db/migrate/20240618151558_create_question_sets.rb b/db/migrate/20240618151558_create_question_sets.rb new file mode 100644 index 00000000..a3393e55 --- /dev/null +++ b/db/migrate/20240618151558_create_question_sets.rb @@ -0,0 +1,9 @@ +class CreateQuestionSets < ActiveRecord::Migration[7.1] + def change + create_table :question_sets do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20240618152147_create_steps.rb b/db/migrate/20240618152147_create_steps.rb new file mode 100644 index 00000000..0e4b5238 --- /dev/null +++ b/db/migrate/20240618152147_create_steps.rb @@ -0,0 +1,12 @@ +class CreateSteps < ActiveRecord::Migration[7.1] + def change + create_table :steps do |t| + t.references :positionable, polymorphic: true, null: false + t.references :next_step, index: true, foreign_key: { to_table: :steps } + t.integer :position + t.references :parent_question_set, index: true, foreign_key: { to_table: :question_sets } + + t.timestamps + end + end +end diff --git a/db/migrate/20240618175604_add_form_to_steps.rb b/db/migrate/20240618175604_add_form_to_steps.rb new file mode 100644 index 00000000..e3c5243c --- /dev/null +++ b/db/migrate/20240618175604_add_form_to_steps.rb @@ -0,0 +1,5 @@ +class AddFormToSteps < ActiveRecord::Migration[7.1] + def change + add_reference :steps, :form, foreign_key: true + end +end diff --git a/db/migrate/20240620114759_add_min_answers_and_max_answers_to_steps.rb b/db/migrate/20240620114759_add_min_answers_and_max_answers_to_steps.rb new file mode 100644 index 00000000..400390d7 --- /dev/null +++ b/db/migrate/20240620114759_add_min_answers_and_max_answers_to_steps.rb @@ -0,0 +1,6 @@ +class AddMinAnswersAndMaxAnswersToSteps < ActiveRecord::Migration[7.1] + def change + add_column :steps, :min_answers, :integer + add_column :steps, :max_answers, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index a5fdb060..70971027 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_10_092310) do +ActiveRecord::Schema[7.1].define(version: 2024_06_20_114759) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -82,6 +82,35 @@ t.index ["form_id"], name: "index_pages_on_form_id" end + create_table "question_sets", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "questions", force: :cascade do |t| + t.string "question_text" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "steps", force: :cascade do |t| + t.string "positionable_type", null: false + t.bigint "positionable_id", null: false + t.bigint "next_step_id" + t.integer "position" + t.bigint "parent_question_set_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.bigint "form_id" + t.integer "min_answers" + t.integer "max_answers" + t.index ["form_id"], name: "index_steps_on_form_id" + t.index ["next_step_id"], name: "index_steps_on_next_step_id" + t.index ["parent_question_set_id"], name: "index_steps_on_parent_question_set_id" + t.index ["positionable_type", "positionable_id"], name: "index_steps_on_positionable" + end + create_table "versions", force: :cascade do |t| t.string "item_type", null: false t.bigint "item_id", null: false @@ -95,4 +124,7 @@ add_foreign_key "made_live_forms", "forms" add_foreign_key "pages", "forms" + add_foreign_key "steps", "forms" + add_foreign_key "steps", "question_sets", column: "parent_question_set_id" + add_foreign_key "steps", "steps", column: "next_step_id" end diff --git a/db/seeds.rb b/db/seeds.rb index 168930fd..bebc3b90 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -92,3 +92,27 @@ what_happens_next_markdown: "Test", ) all_question_types_form.make_live! + +root_question_1 = Question.create!(question_text: "What is your name?") +question_set = QuestionSet.create!(name: "What addresses have you lived at in the past 3 years?") +multiple_answers_question = Question.create!(question_text: "What countries have you travelled to in the past year?") + +step1 = all_question_types_form.steps.create!(positionable: root_question_1, position: 1) +step2 = all_question_types_form.steps.create!(positionable: question_set, position: 2, min_answers: 1, max_answers:5) +step3 = all_question_types_form.steps.create!(positionable: multiple_answers_question, position: 3, min_answers:1, max_answers:10) + +step1.update!(next_step: step2) +step2.update!(next_step: step3) + +set_question_1 = Question.create!(question_text: "What was your address?") +set_question_2 = Question.create!(question_text: "What date did you start living at this address?") +set_question_3 = Question.create!(question_text: "What date did you stop living at this address?") + +set_step1 = question_set.steps.create!(positionable: set_question_1, position: 1) +set_step2 = question_set.steps.create!(positionable: set_question_2, position: 2) +set_step3 = question_set.steps.create!(positionable: set_question_3, position: 3) + +set_step1.update!(next_step: set_step2) +set_step2.update!(next_step: set_step3) + +# Step.all.as_json(include: :positionable) diff --git a/spec/factories/question_sets.rb b/spec/factories/question_sets.rb new file mode 100644 index 00000000..0b1c895b --- /dev/null +++ b/spec/factories/question_sets.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :question_set do + name { "MyString" } + end +end diff --git a/spec/factories/questions.rb b/spec/factories/questions.rb new file mode 100644 index 00000000..eab82e4a --- /dev/null +++ b/spec/factories/questions.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :question do + question_text { "MyString" } + end +end diff --git a/spec/factories/steps.rb b/spec/factories/steps.rb new file mode 100644 index 00000000..82a72dac --- /dev/null +++ b/spec/factories/steps.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :step do + positionable { nil } + next_step { nil } + position { 1 } + parent_question_set { nil } + end +end diff --git a/spec/models/question_set_spec.rb b/spec/models/question_set_spec.rb new file mode 100644 index 00000000..fc0a0e6e --- /dev/null +++ b/spec/models/question_set_spec.rb @@ -0,0 +1,5 @@ +require "rails_helper" + +RSpec.describe QuestionSet, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/question_spec.rb b/spec/models/question_spec.rb new file mode 100644 index 00000000..2606b1cd --- /dev/null +++ b/spec/models/question_spec.rb @@ -0,0 +1,5 @@ +require "rails_helper" + +RSpec.describe Question, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/step_spec.rb b/spec/models/step_spec.rb new file mode 100644 index 00000000..4e23f56c --- /dev/null +++ b/spec/models/step_spec.rb @@ -0,0 +1,5 @@ +require "rails_helper" + +RSpec.describe Step, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end