From b3d9c2d474b44c458433ee6b3ed99583cf56ed6e Mon Sep 17 00:00:00 2001 From: momo3404 Date: Fri, 19 Dec 2025 13:33:12 -0700 Subject: [PATCH 1/5] Update `plans_controller` to include question and answer flag - This optional parameter is added to the plans endpoints in the V2 API --- app/controllers/api/v2/plans_controller.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/controllers/api/v2/plans_controller.rb b/app/controllers/api/v2/plans_controller.rb index 7714e9c892..aeb9144e7b 100644 --- a/app/controllers/api/v2/plans_controller.rb +++ b/app/controllers/api/v2/plans_controller.rb @@ -17,6 +17,8 @@ def show raise Pundit::NotAuthorizedError unless plans_policy.show? @items = [@plan] + @question_and_answer = ActiveModel::Type::Boolean.new.cast(params[:question_and_answer]) + render '/api/v2/plans/index', status: :ok end @@ -26,6 +28,8 @@ def index @plans = PlansPolicy::Scope.new(@resource_owner).resolve @items = paginate_response(results: @plans) + @question_and_answer = ActiveModel::Type::Boolean.new.cast(params[:question_and_answer]) + render '/api/v2/plans/index', status: :ok end end From 62c44989ca1f44e674b3c36c6ea03eeb384ab2c3 Mon Sep 17 00:00:00 2001 From: momo3404 Date: Fri, 19 Dec 2025 13:35:19 -0700 Subject: [PATCH 2/5] Add `fetch_all_q_and_a` function to `research_output_presenter` - This function fetches all questions and answers belonging to a plan. --- .../api/v2/research_output_presenter.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/presenters/api/v2/research_output_presenter.rb b/app/presenters/api/v2/research_output_presenter.rb index fc44055b2d..8a64113da3 100644 --- a/app/presenters/api/v2/research_output_presenter.rb +++ b/app/presenters/api/v2/research_output_presenter.rb @@ -71,6 +71,22 @@ def fetch_q_and_a(themes:) end ret.select { |item| item[:description].present? } end + + # Fetch all questions and answers from a plan, regardless of theme + def fetch_all_q_and_a(plan:) + return [] unless plan&.questions.present? + + plan.questions.filter_map do |q| + a = plan.answers.find { |ans| ans.question_id == q.id } + next unless a.present? && !a.blank? + + { + title: "Question #{q.number || q.id}", + question: q.text.to_s, + answer: a.text.to_s + } + end + end # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity end end From 8f3beaf6714584cd6c1c52d230b0583008f27c2a Mon Sep 17 00:00:00 2001 From: momo3404 Date: Fri, 19 Dec 2025 13:36:00 -0700 Subject: [PATCH 3/5] Update `_show,json.jbuilder` to include questions and answers --- app/views/api/v2/plans/_show.json.jbuilder | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/views/api/v2/plans/_show.json.jbuilder b/app/views/api/v2/plans/_show.json.jbuilder index 0de52775a3..f3ad018812 100644 --- a/app/views/api/v2/plans/_show.json.jbuilder +++ b/app/views/api/v2/plans/_show.json.jbuilder @@ -57,6 +57,24 @@ unless @minimal outputs = plan.research_outputs.any? ? plan.research_outputs : [plan] + if @question_and_answer + json.questions_and_answers do + outputs.each do |output| + presenter = Api::V2::ResearchOutputPresenter.new(output: output) + q_and_a = presenter.send(:fetch_all_q_and_a, plan: plan) + next if q_and_a.blank? + + json.set! output.id.to_s do + json.array! q_and_a do |item| + json.title item[:title] + json.question item[:question] + json.answer item[:answer] + end + end + end + end + end + json.dataset outputs do |output| json.partial! "api/v2/datasets/show", output: output end From ccc769949e6fc6cefe1cf3988f2787c1d18fa9c6 Mon Sep 17 00:00:00 2001 From: momo3404 Date: Mon, 22 Dec 2025 12:52:51 -0700 Subject: [PATCH 4/5] Reorganize files and functions - Moved 'fetch_all_q_and_a' from research_output_present to plan_presenter - Moved q_and_a json to be inside extensions --- app/presenters/api/v2/plan_presenter.rb | 16 +++++++++ .../api/v2/research_output_presenter.rb | 16 --------- app/views/api/v2/plans/_show.json.jbuilder | 35 +++++++++---------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/app/presenters/api/v2/plan_presenter.rb b/app/presenters/api/v2/plan_presenter.rb index 204cd68011..14296b71a8 100644 --- a/app/presenters/api/v2/plan_presenter.rb +++ b/app/presenters/api/v2/plan_presenter.rb @@ -35,6 +35,22 @@ def identifier Identifier.new(value: Rails.application.routes.url_helpers.api_v2_plan_url(@plan)) end + # Fetch all questions and answers from a plan, regardless of theme + def fetch_all_q_and_a(plan:) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity + return [] unless plan&.questions.present? + + plan.questions.filter_map do |q| + a = plan.answers.find { |ans| ans.question_id == q.id } + next unless a.present? && !a.blank? + + { + title: "Question #{q.number || q.id}", + question: q.text.to_s, + answer: a.text.to_s + } + end + end + private # Retrieve the answers that have the Budget theme diff --git a/app/presenters/api/v2/research_output_presenter.rb b/app/presenters/api/v2/research_output_presenter.rb index 8a64113da3..fc44055b2d 100644 --- a/app/presenters/api/v2/research_output_presenter.rb +++ b/app/presenters/api/v2/research_output_presenter.rb @@ -71,22 +71,6 @@ def fetch_q_and_a(themes:) end ret.select { |item| item[:description].present? } end - - # Fetch all questions and answers from a plan, regardless of theme - def fetch_all_q_and_a(plan:) - return [] unless plan&.questions.present? - - plan.questions.filter_map do |q| - a = plan.answers.find { |ans| ans.question_id == q.id } - next unless a.present? && !a.blank? - - { - title: "Question #{q.number || q.id}", - question: q.text.to_s, - answer: a.text.to_s - } - end - end # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity end end diff --git a/app/views/api/v2/plans/_show.json.jbuilder b/app/views/api/v2/plans/_show.json.jbuilder index f3ad018812..20ccbcde3f 100644 --- a/app/views/api/v2/plans/_show.json.jbuilder +++ b/app/views/api/v2/plans/_show.json.jbuilder @@ -57,24 +57,6 @@ unless @minimal outputs = plan.research_outputs.any? ? plan.research_outputs : [plan] - if @question_and_answer - json.questions_and_answers do - outputs.each do |output| - presenter = Api::V2::ResearchOutputPresenter.new(output: output) - q_and_a = presenter.send(:fetch_all_q_and_a, plan: plan) - next if q_and_a.blank? - - json.set! output.id.to_s do - json.array! q_and_a do |item| - json.title item[:title] - json.question item[:question] - json.answer item[:answer] - end - end - end - end - end - json.dataset outputs do |output| json.partial! "api/v2/datasets/show", output: output end @@ -86,5 +68,22 @@ unless @minimal json.title template.title end end + + if @question_and_answer + json.questions_and_answers do + outputs.each do |output| + q_and_a = presenter.send(:fetch_all_q_and_a, plan: plan) + next if q_and_a.blank? + + json.set! output.id.to_s do + json.array! q_and_a do |item| + json.title item[:title] + json.question item[:question] + json.answer item[:answer] + end + end + end + end + end end end From 865d5de47ceead15c407b17d166039b9a8271f62 Mon Sep 17 00:00:00 2001 From: momo3404 Date: Wed, 24 Dec 2025 10:37:53 -0700 Subject: [PATCH 5/5] Remove plan parameter from fetch function --- app/presenters/api/v2/plan_presenter.rb | 8 ++++---- app/views/api/v2/plans/_show.json.jbuilder | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/presenters/api/v2/plan_presenter.rb b/app/presenters/api/v2/plan_presenter.rb index 14296b71a8..0f0257f093 100644 --- a/app/presenters/api/v2/plan_presenter.rb +++ b/app/presenters/api/v2/plan_presenter.rb @@ -36,11 +36,11 @@ def identifier end # Fetch all questions and answers from a plan, regardless of theme - def fetch_all_q_and_a(plan:) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity - return [] unless plan&.questions.present? + def fetch_all_q_and_a # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity + return [] unless @plan&.questions.present? - plan.questions.filter_map do |q| - a = plan.answers.find { |ans| ans.question_id == q.id } + @plan.questions.filter_map do |q| + a = @plan.answers.find { |ans| ans.question_id == q.id } next unless a.present? && !a.blank? { diff --git a/app/views/api/v2/plans/_show.json.jbuilder b/app/views/api/v2/plans/_show.json.jbuilder index 20ccbcde3f..1ce53c235d 100644 --- a/app/views/api/v2/plans/_show.json.jbuilder +++ b/app/views/api/v2/plans/_show.json.jbuilder @@ -72,7 +72,7 @@ unless @minimal if @question_and_answer json.questions_and_answers do outputs.each do |output| - q_and_a = presenter.send(:fetch_all_q_and_a, plan: plan) + q_and_a = presenter.send(:fetch_all_q_and_a) next if q_and_a.blank? json.set! output.id.to_s do