Skip to content

Feature/test cases#343

Open
akhilkumar2004 wants to merge 23 commits into
expertiza:mainfrom
DevPatel1106:feature/test-cases
Open

Feature/test cases#343
akhilkumar2004 wants to merge 23 commits into
expertiza:mainfrom
DevPatel1106:feature/test-cases

Conversation

@akhilkumar2004

@akhilkumar2004 akhilkumar2004 commented Apr 28, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Response API for creating, viewing, and updating responses with authorization and task-order enforcement
    • Student task endpoints to fetch task queue, start tasks, and get next tasks; plus a task ordering/queue system
  • Chores

    • Database and linting/format configuration adjustments; README formatting tweaks
    • Improved file-read resilience and minor config cleanups
  • Tests

    • New comprehensive specs for responses, student tasks, and task-ordering behaviors

DevPatel1106 and others added 20 commits March 23, 2026 15:29
…f them pass!

run 'rails test' and you can see all 30 test cases passing!
run 'rails test' to test all files.
Feature/test cases has the Rspec testing done for the task_ordering/, student_tasks_controller, responses_controller files.
This reverts commit 6d0871f, reversing
changes made to 6a3bb7c.
…e in which the guidelines did not specifically tell us to do.
@github-actions

github-actions Bot commented Apr 28, 2026

Copy link
Copy Markdown
5 Warnings
⚠️ Pull request is too big (more than 500 LoC).
⚠️ Pull request has duplicated commit messages.
⚠️ Pull request contains TODO or FIXME comments.
⚠️ Pull request modifies markdown files (*.md). Make sure you have a good reason.
⚠️ Pull request modifies config or setup files: config/database.yml.

Generated by 🚫 Danger

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a task-ordering system and APIs for student task progression and responses: new TaskOrdering models and factory/queue, controllers/endpoints for responses and student task flows with authorization/enforcement, Assignment/StudentTask helpers, route/config changes, and extensive spec coverage.

Changes

Cohort / File(s) Summary
Routing & Config
config/routes.rb, config/database.yml, .rubocop.yml
Adds responses resource and student task collection routes (queue, next_task, start_task); removes production DB block and fixes test DB name; normalizes quoted pattern in RuboCop config and fixes trailing newline.
Controllers
app/controllers/application_controller.rb, app/controllers/responses_controller.rb, app/controllers/student_tasks_controller.rb
Registers new callbacks in ApplicationController; adds ResponsesController (show, create, update) with authorization and task-order enforcement; adds StudentTasksController actions (queue, next_task, start_task) and nested TaskItem classes handling task serialization and completion logic.
TaskOrdering Models
app/models/task_ordering/...
app/models/task_ordering/base_task.rb, .../review_task.rb, .../quiz_task.rb, .../task_factory.rb, .../task_queue.rb
Introduces BaseTask, ReviewTask, QuizTask, a TaskFactory to construct tasks based on duties/questionnaires, and a TaskQueue to order tasks, materialize response/response_map objects, and evaluate prior-task completion.
Core Models
app/models/assignment.rb, app/models/student_task.rb
Adds Assignment helpers to fetch review/quiz questionnaires and build a task queue; StudentTask gains assignment_id, safer creation/parsing logic, improved deadline parsing, and as_json serialization.
Specs & Test Helpers
spec/models/task_ordering_spec.rb, spec/requests/api/v1/responses_controller_spec.rb, spec/requests/api/v1/student_tasks_controller_spec.rb, spec/rails_helper.rb
Adds comprehensive model and request specs for task ordering, student tasks, and responses; adjusts spec support loading and includes test helpers; many new/updated test cases covering auth, errors, and ordering rules.
Utilities & CI
Dangerfile, README.md
Improves safe_read to handle missing/invalid-encoding files and rescues errors; minor README formatting tweaks.
Other
spec/... (many new/updated spec files)
Large additions/changes to test fixtures and request/spec coverage exercising the new flows and authorization rules.

Sequence Diagram

sequenceDiagram
    actor Student
    participant StudentTasksController as "StudentTasksController"
    participant TaskQueue as "TaskOrdering::TaskQueue"
    participant TaskFactory as "TaskOrdering::TaskFactory"
    participant BaseTask as "TaskOrdering::BaseTask"
    participant Assignment as "Assignment"
    participant DB as "Database"
    participant ResponsesController as "ResponsesController"

    Student->>StudentTasksController: GET /student_tasks/queue (assignment_id)
    StudentTasksController->>TaskQueue: initialize(assignment, team_participant)
    TaskQueue->>TaskFactory: build(assignment, team_participant)
    TaskFactory->>Assignment: quiz_questionnaire_for_review_flow
    TaskFactory->>DB: fetch ReviewResponseMaps / QuizResponseMaps
    TaskFactory-->>TaskQueue: return ordered tasks
    TaskQueue->>BaseTask: ensure_response_objects! (each task)
    BaseTask->>DB: find_or_create Response / ResponseMap
    TaskQueue-->>StudentTasksController: tasks JSON
    StudentTasksController-->>Student: 200 [task queue]

    Student->>StudentTasksController: POST /student_tasks/next_task
    StudentTasksController->>TaskQueue: select first incomplete
    TaskQueue-->>StudentTasksController: next task or completion
    StudentTasksController-->>Student: next task payload / completion

    Student->>StudentTasksController: POST /student_tasks/start_task (map_id)
    StudentTasksController->>TaskQueue: task_for_map_id(map_id)
    TaskQueue->>BaseTask: ensure_response!(round:1)
    BaseTask->>DB: create/initialize Response (unsubmitted)
    StudentTasksController-->>Student: started task payload

    Student->>ResponsesController: POST /responses (map_id, content)
    ResponsesController->>TaskQueue: enforce_task_order!(map_id)
    TaskQueue->>DB: check prior Responses submitted
    ResponsesController->>DB: create/update Response
    ResponsesController-->>Student: 201 / 422 / 403 / 404

    Student->>ResponsesController: PATCH /responses/:id (is_submitted)
    ResponsesController->>DB: update Response
    ResponsesController-->>Student: 200 / 403 / 404 / 422
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 I thumped my paw and sorted the queue,
Quizzes then reviews in tidy view,
Maps and responses lined up bright,
Hop — each task steps into light,
A carrot waits for every right-write!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feature/test cases' is vague and generic, using non-descriptive terms that don't convey meaningful information about the substantial changes in this changeset. Provide a more specific title that describes the primary feature or functionality being added, such as 'Add task queue and response management endpoints' or similar.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (13)
app/models/task_ordering/task_queue.rb (2)

10-15: Consider memoizing tasks to avoid repeated TaskFactory.build calls.

tasks is called multiple times within methods like prior_tasks_complete_for? (lines 45, 46, 49 via take_while), map_ids, and ensure_response_objects!. Each call invokes TaskFactory.build, which likely performs database queries.

Memoizing the result would improve performance.

♻️ Proposed fix
     def tasks
-      TaskFactory.build(
+      `@tasks` ||= TaskFactory.build(
         assignment: `@assignment`,
         team_participant: `@team_participant`
       )
     end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/models/task_ordering/task_queue.rb` around lines 10 - 15, The tasks
method calls TaskFactory.build multiple times and should be memoized to avoid
repeated expensive builds; update the tasks method to cache its result using an
instance variable (e.g. replace current TaskFactory.build call in tasks with an
assignment like `@tasks` ||= TaskFactory.build(...)) so subsequent calls from
methods like prior_tasks_complete_for?, map_ids, and ensure_response_objects!
reuse the same array instead of rebuilding it each time.

51-52: Add final newline.

Missing final newline as flagged by RuboCop.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/models/task_ordering/task_queue.rb` around lines 51 - 52, The file
defining the TaskOrdering::TaskQueue class is missing a trailing newline at
end-of-file (RuboCop complaint); update app/models/task_ordering/task_queue.rb
so that the file ends with a single newline character (i.e., ensure there is a
blank line after the final "end" of the TaskQueue class).
app/models/task_ordering/quiz_task.rb (1)

35-36: Add final newline.

Missing final newline as flagged by RuboCop.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/models/task_ordering/quiz_task.rb` around lines 35 - 36, The file
defining TaskOrdering::QuizTask is missing a final newline; open the file
containing the TaskOrdering module / QuizTask class (QuizTask) and add a single
trailing newline character at EOF so the file ends with a newline to satisfy
RuboCop.
spec/rails_helper.rb (1)

74-79: Add final newline.

Missing final newline as flagged by RuboCop. Most editors and version control systems expect files to end with a newline.

🔧 Proposed fix
 Shoulda::Matchers.configure do |config|
   config.integrate do |with|
     with.test_framework :rspec
     with.library :rails
   end
-end
+end
+
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/rails_helper.rb` around lines 74 - 79, The file ends without a trailing
newline; update the Shoulda::Matchers.configure block by adding a final newline
at the end of the file so the file terminates with a newline character (ensure
the last line after the config.integrate / with.library :rails block ends with a
newline).
config/routes.rb (1)

12-222: Fix inconsistent indentation and formatting throughout the routes file.

The routes file has significant formatting inconsistencies flagged by RuboCop:

  • Inconsistent indentation (resources not aligned)
  • Trailing whitespace on multiple lines (60, 84, 85, 116, 175, 178, 202, 204)
  • Missing spaces after commas (lines 28-31, 33-34, 39)
  • Missing spaces after colons (lines 80-81)
  • Missing final newline

Consider running rubocop -a config/routes.rb to auto-fix these style issues. The file should use consistent 2-space indentation for all resource blocks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/routes.rb` around lines 12 - 222, The routes file has inconsistent
indentation and spacing across many resource blocks (e.g., resources :roles,
resources :users, resources :questions, resources :assignments and nested
resources :duties), trailing whitespace on several lines, missing spaces after
commas and colons, and no final newline; fix by normalizing to 2-space
indentation for all resource/member/collection blocks, remove trailing spaces,
add missing spaces after commas and colons in route option lists, ensure the
file ends with a newline, and then run rubocop -a config/routes.rb to auto-apply
remaining style fixes.
app/controllers/student_tasks_controller.rb (1)

40-63: Consider extracting authorization and queue building into a before_action.

The start_task method has high complexity (ABC size 31.53 per static analysis). The authorization check and queue building are repeated patterns that could be extracted.

♻️ Refactor suggestion
before_action :authorize_and_build_task_queue, only: %i[start_task]

private

def authorize_and_build_task_queue
  `@map` = ResponseMap.find_by(id: params[:response_map_id])
  return render json: { error: "ResponseMap not found" }, status: :not_found unless `@map`

  participant = `@map.reviewer`
  return render json: { error: "Unauthorized" }, status: :forbidden unless participant.user_id == current_user.id

  team_participant = TeamsParticipant.find_by(participant_id: participant.id)
  `@queue` = TaskOrdering::TaskQueue.new(participant.assignment, team_participant)
end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/student_tasks_controller.rb` around lines 40 - 63, Extract
the authorization and queue setup from start_task into a before_action named
authorize_and_build_task_queue: locate ResponseMap lookup and assign it to `@map`,
validate current_user via `@map.reviewer` (returning the same JSON errors on
failure), find TeamsParticipant by participant.id, and initialize `@queue` =
TaskOrdering::TaskQueue.new(participant.assignment, team_participant); then
update start_task to use `@map` and `@queue` (replace local variables map,
participant, team_participant, assignment, queue) and keep the remaining
task-finding and completion checks intact. Ensure the before_action is applied
only to start_task and preserves the original JSON error responses.
spec/requests/api/v1/student_tasks_controller_spec.rb (3)

195-197: Simplify redundant assertion.

expect([200]).to include(response.status) is unnecessarily verbose when only one status is acceptable.

-        expect([200]).to include(response.status)
+        expect(response.status).to eq(200)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/requests/api/v1/student_tasks_controller_spec.rb` around lines 195 -
197, The assertion inside the run_test! block is overly verbose; replace the
array-inclusion check with a direct status assertion—update the expectation in
the run_test! do |response| block (referencing run_test! and response.status) to
assert the single accepted status directly (for example using
expect(response.status).to eq(200) or expect(response).to
have_http_status(:ok)).

238-243: Swagger response declaration doesn't match test expectations.

The response block declares '200' but the assertion accepts [200, 403]. This generates misleading API documentation since Swagger will only document the 200 case.

Consider splitting into two explicit response blocks or aligning the declaration with actual behavior:

♻️ Suggested fix
-      response '200', 'task started or blocked by queue ordering' do
+      response '200', 'task started successfully' do
         let(:body) { { response_map_id: review_map.id } }
         run_test! do |response|
-          expect([200, 403]).to include(response.status)
+          # Assumes test fixture allows immediate start
+          expect(response.status).to eq(200)
         end
       end
+
+      response '403', 'blocked by incomplete prior tasks' do
+        # Setup fixture with incomplete prior task
+        let(:body) { { response_map_id: review_map.id } }
+        run_test! do |response|
+          expect(response.status).to eq(403)
+        end
+      end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/requests/api/v1/student_tasks_controller_spec.rb` around lines 238 -
243, The Swagger response label in the spec block is incorrect: the example
declares response '200' but the test assertion accepts [200, 403] (in the
response block that wraps run_test!), which will misdocument the API; update the
spec by either splitting into two response blocks (create a separate response
'403' block with the same let(:body) and run_test!/verifications) or change the
assertion to only expect 200 so the declared response matches the actual
assertion in the response '200' block that contains run_test! and the
expect([...]). Locate the response block around the test (the response '200' do
... run_test! do |response| expect([200, 403]).to include(response.status) end
end) and apply one of the two fixes to ensure Swagger docs reflect both outcomes
or the test matches the documented single outcome.

124-129: Test case doesn't verify the "null" behavior it describes.

The test is labeled "participant not found returns null" but only checks the status code without verifying the response body. This makes the test incomplete and the description misleading.

Consider verifying the actual null/nil response:

run_test! do |response|
  data = JSON.parse(response.body)
  expect(data).to be_nil
end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/requests/api/v1/student_tasks_controller_spec.rb` around lines 124 -
129, The test "participant not found returns null" currently only asserts the
HTTP status; update the example block around response '200' that uses run_test!
to also parse the response body (JSON.parse(response.body)) and assert the body
is nil (expect(data).to be_nil) so the spec verifies the described "null"
behavior for a missing participant in the run_test! block.
app/controllers/responses_controller.rb (1)

89-114: enforce_task_order! duplicates authorization logic.

Line 91-94 checks participant.user_id == current_user.id, but find_and_authorize_map_for_create (lines 76-78) already does this check before create runs. For update, action_allowed? performs similar verification.

This redundancy could be removed by relying on the existing callbacks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/responses_controller.rb` around lines 89 - 114, Remove the
redundant current_user authorization check inside enforce_task_order! (the
participant.user_id == current_user.id branch) since map authorization is
already handled by find_and_authorize_map_for_create for create and by
action_allowed? for update; update enforce_task_order! to assume the caller has
already authorized the map (keep the TeamsParticipant lookup,
TaskOrdering::TaskQueue checks and error responses intact) and add a short
comment in enforce_task_order! noting that caller callbacks must perform
user/map authorization (referencing enforce_task_order!,
find_and_authorize_map_for_create, and action_allowed?).
spec/requests/api/v1/responses_controller_spec.rb (1)

73-80: Consider documenting why validation is skipped.

Using save!(validate: false) in tests can mask validation issues that would occur in production. If this is necessary due to fixture complexity, add a comment explaining why.

# Skip validation because ReviewResponseMap requires associations not relevant to this test
map.save!(validate: false)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/requests/api/v1/responses_controller_spec.rb` around lines 73 - 80, The
test currently uses ReviewResponseMap.new and calls map.save!(validate: false)
which can hide validation issues; add an inline comment above the save
explaining why validation is skipped (for example, which required associations
or callbacks are irrelevant to this spec) and when possible prefer creating the
object via valid factory/fixtures or explicitly stub the irrelevant validations
instead of disabling them globally; reference ReviewResponseMap,
map.save!(validate: false), and the map variable in the comment so future
readers understand the rationale.
app/models/task_ordering/task_factory.rb (1)

21-46: Consider extracting task creation logic to reduce complexity.

The build method has high cyclomatic complexity (12 per static analysis). Extracting the quiz and review task creation could improve readability.

♻️ Refactor suggestion
def self.build(assignment:, team_participant:)
  participant = team_participant.participant
  duty = find_duty(team_participant, participant)
  review_maps = find_review_maps(team_participant, assignment)
  
  if review_maps.any?
    build_tasks_from_maps(assignment, team_participant, duty, review_maps)
  elsif allows_quiz?(duty) && assignment.quiz_questionnaire_for_review_flow
    [QuizTask.new(assignment: assignment, team_participant: team_participant, review_map: nil)]
  else
    []
  end
end

private_class_method def self.build_tasks_from_maps(assignment, team_participant, duty, review_maps)
  tasks = []
  quiz_questionnaire = assignment.quiz_questionnaire_for_review_flow
  has_existing_quiz_maps = QuizResponseMap.where(reviewer_id: team_participant.participant_id).exists?

  review_maps.each do |review_map|
    tasks.concat(build_tasks_for_map(assignment, team_participant, duty, review_map, quiz_questionnaire, has_existing_quiz_maps))
  end
  tasks
end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/models/task_ordering/task_factory.rb` around lines 21 - 46, The build
method in TaskFactory is too complex; extract quiz/review creation into helpers:
create private_class_method build_tasks_from_maps(assignment, team_participant,
duty, review_maps) that iterates review_maps and calls a new helper
build_tasks_for_map(assignment, team_participant, duty, review_map,
quiz_questionnaire, has_existing_quiz_maps) which returns an array of
QuizTask/ReviewTask instances; move the QuizTask-with-nil-review_map branch into
the top-level build to return [QuizTask.new(...)] when allows_quiz?(duty) &&
assignment.quiz_questionnaire_for_review_flow, and compute quiz_questionnaire
and has_existing_quiz_maps (via QuizResponseMap.where(...).exists?) once in
build_tasks_from_maps to avoid redundant checks; ensure callers use allows_quiz?
and allows_review? to decide creation and that build now returns an array
(possibly empty).
app/models/student_task.rb (1)

56-64: Fallback deadline is far in the future, which affects sort order.

When stage_deadline is nil or unparseable, the fallback Time.current + 1.year places these tasks at the end of the sorted list in from_user. This seems intentional but worth documenting.

     def parse_stage_deadline(value)
+      # Default to 1 year in the future so tasks without deadlines sort last
       return Time.current + 1.year if value.nil?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/models/student_task.rb` around lines 56 - 64, The parse_stage_deadline
method uses Time.current + 1.year as a fallback which intentionally pushes
nil/unparseable stage_deadline values to the end of sorted lists (e.g.
from_user); make this explicit by extracting the fallback into a named constant
(e.g. FUTURE_STAGE_DEADLINE = 1.year.from_now or 1.year) and replacing the
inline Time.current + 1.year with that constant, add a short code comment above
parse_stage_deadline explaining that this long-future default is intentional to
affect sort order, and update any relevant tests or callers that assume the
fallback value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/controllers/application_controller.rb`:
- Around line 12-13: The new callbacks prepend_before_action :set_response and
before_action :find_and_authorize_map_for_create were added to
ApplicationController but the methods set_response and
find_and_authorize_map_for_create are defined only in ResponsesController and
will raise NoMethodError in other controllers; remove those two callback lines
from ApplicationController and instead add them inside ResponsesController (use
prepend_before_action :set_response, only: %i[show update] and before_action
:find_and_authorize_map_for_create, only: %i[create]) so the callbacks live with
the methods they call.

In `@app/controllers/responses_controller.rb`:
- Around line 76-78: Fix the typo in the error message inside
ResponsesController where the unauthorized branch renders { error: "You are not
authorized to create this responses" } — change the string to "You are not
authorized to create this response" so the grammar is correct (look for the
render json call in the unauthorized check using `@map.reviewer.user_id` and
current_user.id).
- Around line 3-5: Remove the duplicate before_action callbacks in
ResponsesController: delete the prepend_before_action :set_response, only:
%i[show update] and before_action :find_and_authorize_map_for_create, only:
%i[create] lines so the controller relies on the inherited callbacks defined in
ApplicationController; ensure no other local callback definitions remain that
would reintroduce duplication for set_response or
find_and_authorize_map_for_create.
- Around line 32-34: Replace the non-atomic selection/creation pattern around
Response (the `Response.where(map_id: `@map.id`, round:
round).order(:created_at).last || Response.new(...)` block) with an atomic
find-or-create operation (e.g., use Response.find_or_create_by(map_id: `@map.id`,
round: round) or a transaction with locking) and add/ensure a database-level
unique constraint on (map_id, round) to prevent duplicates; update any
save/error handling around the Response creation to handle uniqueness validation
failures or ActiveRecord::RecordNotUnique exceptions accordingly.

In `@app/controllers/student_tasks_controller.rb`:
- Around line 69-110: BaseTaskItem duplicates logic from TaskOrdering::BaseTask
(ensure_response!, completed?, to_h/to_task_hash); refactor by removing
duplication: either make BaseTaskItem inherit from TaskOrdering::BaseTask, or
extract the shared methods (ensure_response!, completed?, to_h/alias
to_task_hash and any helpers like participant/response_map usage) into a module
(e.g., TaskItemShared) and include it in both classes; update references to
response_map/participant methods if moved to keep behavior identical and run
tests to ensure no behavior change.

In `@app/models/student_task.rb`:
- Around line 34-39: The view action should handle the case where
StudentTask.from_participant_id(params[:id]) returns nil; update the
controller's view method to call StudentTask.from_participant_id(params[:id]),
check the result, and if nil immediately render json: { error: "Not found" }
with status :not_found, otherwise render the `@student_task` with status :ok;
reference the view action and StudentTask.from_participant_id to locate and
apply this change.

In `@app/models/task_ordering/base_task.rb`:
- Around line 49-60: Add a safe base implementation of task_type on BaseTask so
calling to_task_hash on a BaseTask instance does not raise NoMethodError: define
a task_type method in the BaseTask class (similar to the existing response_map
pattern) that returns nil (or a sensible default) or explicitly raises
NotImplementedError if you prefer forcing subclasses to implement it; update the
class by adding this task_type method so to_task_hash can call task_type safely.

In `@app/models/task_ordering/quiz_task.rb`:
- Line 33: The current code creates a QuizResponseMap with `@response_map` =
QuizResponseMap.new(attrs).tap { |m| m.save!(validate: false) } which bypasses
model validations; change this to ensure validations run by removing the
validate: false flag and either validate before saving or use
conditional/explicit validations on QuizResponseMap to permit these attrs.
Specifically, update the creation flow for QuizResponseMap so you build the
record (QuizResponseMap.new(attrs)), call valid? (or handle model.errors) and
then call save! without validate: false, or refactor the model validations
(using conditional validators) so the record can be saved validly when this path
is used.
- Around line 17-21: The current code uses 0 as a fallback for reviewee_id in
QuizResponseMap.find_by, which is invalid; update the logic to stop using 0:
either (A) explicitly require review_map and raise a clear error when review_map
is nil (e.g. check review_map and raise ArgumentError or return early) before
calling QuizResponseMap.find_by(reviewer_id: team_participant.participant_id,
reviewee_id: review_map.reviewee_id), or (B) let review_map&.reviewee_id return
nil and change the lookup to handle nil explicitly (use where(reviewer_id: ...,
reviewee_id: review_map&.reviewee_id).take with separate handling when
review_map is nil to avoid matching unintended NULL rows); reference
QuizResponseMap.find_by, team_participant.participant_id, and review_map to
locate the code and implement one of these fixes.

In `@config/database.yml`:
- Line 14: The test DB names are inconsistent: database.yml sets database:
reimplementation_back_end_test while spec's ENV['DATABASE_URL'] uses
reimplementation_test; make them identical. Update either the database key in
database.yml (database: reimplementation_test) or change the DATABASE_URL
construction in spec/rails_helper.rb to reference reimplementation_back_end_test
so both the database.yml "database" value and the ENV['DATABASE_URL'] string
match exactly.
- Around line 12-14: Restore a production database configuration block in
database.yml (or explicitly document using DATABASE_URL) so production won't
fail; add a production: entry that mirrors the development pattern by reading
ENV['DATABASE_URL'] (or the specific adapter/host/name/username/password keys
used previously), or update config/environments/production.rb to load the same
ENV variable; reference the missing production block in database.yml and the
ENV['DATABASE_URL'] usage in development to ensure consistency and explicit
behavior for production deployments.

In `@spec/requests/api/v1/responses_controller_spec.rb`:
- Around line 137-146: The stub on the local assignment object won't affect the
Assignment instance the controller loads via participant.assignment (used by
TaskOrdering::TaskQueue → TaskFactory.build), so replace the per-object stub
with a class-level or persisted approach: either use an any-instance stub for
Assignment (so quiz_questionnaire_for_review_flow is intercepted on the
DB-loaded instance) or attach the questionnaire to the assignment record in the
database so the real assignment instance returns the desired questionnaire when
TaskFactory.build calls quiz_questionnaire_for_review_flow.

---

Nitpick comments:
In `@app/controllers/responses_controller.rb`:
- Around line 89-114: Remove the redundant current_user authorization check
inside enforce_task_order! (the participant.user_id == current_user.id branch)
since map authorization is already handled by find_and_authorize_map_for_create
for create and by action_allowed? for update; update enforce_task_order! to
assume the caller has already authorized the map (keep the TeamsParticipant
lookup, TaskOrdering::TaskQueue checks and error responses intact) and add a
short comment in enforce_task_order! noting that caller callbacks must perform
user/map authorization (referencing enforce_task_order!,
find_and_authorize_map_for_create, and action_allowed?).

In `@app/controllers/student_tasks_controller.rb`:
- Around line 40-63: Extract the authorization and queue setup from start_task
into a before_action named authorize_and_build_task_queue: locate ResponseMap
lookup and assign it to `@map`, validate current_user via `@map.reviewer` (returning
the same JSON errors on failure), find TeamsParticipant by participant.id, and
initialize `@queue` = TaskOrdering::TaskQueue.new(participant.assignment,
team_participant); then update start_task to use `@map` and `@queue` (replace local
variables map, participant, team_participant, assignment, queue) and keep the
remaining task-finding and completion checks intact. Ensure the before_action is
applied only to start_task and preserves the original JSON error responses.

In `@app/models/student_task.rb`:
- Around line 56-64: The parse_stage_deadline method uses Time.current + 1.year
as a fallback which intentionally pushes nil/unparseable stage_deadline values
to the end of sorted lists (e.g. from_user); make this explicit by extracting
the fallback into a named constant (e.g. FUTURE_STAGE_DEADLINE = 1.year.from_now
or 1.year) and replacing the inline Time.current + 1.year with that constant,
add a short code comment above parse_stage_deadline explaining that this
long-future default is intentional to affect sort order, and update any relevant
tests or callers that assume the fallback value.

In `@app/models/task_ordering/quiz_task.rb`:
- Around line 35-36: The file defining TaskOrdering::QuizTask is missing a final
newline; open the file containing the TaskOrdering module / QuizTask class
(QuizTask) and add a single trailing newline character at EOF so the file ends
with a newline to satisfy RuboCop.

In `@app/models/task_ordering/task_factory.rb`:
- Around line 21-46: The build method in TaskFactory is too complex; extract
quiz/review creation into helpers: create private_class_method
build_tasks_from_maps(assignment, team_participant, duty, review_maps) that
iterates review_maps and calls a new helper build_tasks_for_map(assignment,
team_participant, duty, review_map, quiz_questionnaire, has_existing_quiz_maps)
which returns an array of QuizTask/ReviewTask instances; move the
QuizTask-with-nil-review_map branch into the top-level build to return
[QuizTask.new(...)] when allows_quiz?(duty) &&
assignment.quiz_questionnaire_for_review_flow, and compute quiz_questionnaire
and has_existing_quiz_maps (via QuizResponseMap.where(...).exists?) once in
build_tasks_from_maps to avoid redundant checks; ensure callers use allows_quiz?
and allows_review? to decide creation and that build now returns an array
(possibly empty).

In `@app/models/task_ordering/task_queue.rb`:
- Around line 10-15: The tasks method calls TaskFactory.build multiple times and
should be memoized to avoid repeated expensive builds; update the tasks method
to cache its result using an instance variable (e.g. replace current
TaskFactory.build call in tasks with an assignment like `@tasks` ||=
TaskFactory.build(...)) so subsequent calls from methods like
prior_tasks_complete_for?, map_ids, and ensure_response_objects! reuse the same
array instead of rebuilding it each time.
- Around line 51-52: The file defining the TaskOrdering::TaskQueue class is
missing a trailing newline at end-of-file (RuboCop complaint); update
app/models/task_ordering/task_queue.rb so that the file ends with a single
newline character (i.e., ensure there is a blank line after the final "end" of
the TaskQueue class).

In `@config/routes.rb`:
- Around line 12-222: The routes file has inconsistent indentation and spacing
across many resource blocks (e.g., resources :roles, resources :users, resources
:questions, resources :assignments and nested resources :duties), trailing
whitespace on several lines, missing spaces after commas and colons, and no
final newline; fix by normalizing to 2-space indentation for all
resource/member/collection blocks, remove trailing spaces, add missing spaces
after commas and colons in route option lists, ensure the file ends with a
newline, and then run rubocop -a config/routes.rb to auto-apply remaining style
fixes.

In `@spec/rails_helper.rb`:
- Around line 74-79: The file ends without a trailing newline; update the
Shoulda::Matchers.configure block by adding a final newline at the end of the
file so the file terminates with a newline character (ensure the last line after
the config.integrate / with.library :rails block ends with a newline).

In `@spec/requests/api/v1/responses_controller_spec.rb`:
- Around line 73-80: The test currently uses ReviewResponseMap.new and calls
map.save!(validate: false) which can hide validation issues; add an inline
comment above the save explaining why validation is skipped (for example, which
required associations or callbacks are irrelevant to this spec) and when
possible prefer creating the object via valid factory/fixtures or explicitly
stub the irrelevant validations instead of disabling them globally; reference
ReviewResponseMap, map.save!(validate: false), and the map variable in the
comment so future readers understand the rationale.

In `@spec/requests/api/v1/student_tasks_controller_spec.rb`:
- Around line 195-197: The assertion inside the run_test! block is overly
verbose; replace the array-inclusion check with a direct status assertion—update
the expectation in the run_test! do |response| block (referencing run_test! and
response.status) to assert the single accepted status directly (for example
using expect(response.status).to eq(200) or expect(response).to
have_http_status(:ok)).
- Around line 238-243: The Swagger response label in the spec block is
incorrect: the example declares response '200' but the test assertion accepts
[200, 403] (in the response block that wraps run_test!), which will misdocument
the API; update the spec by either splitting into two response blocks (create a
separate response '403' block with the same let(:body) and
run_test!/verifications) or change the assertion to only expect 200 so the
declared response matches the actual assertion in the response '200' block that
contains run_test! and the expect([...]). Locate the response block around the
test (the response '200' do ... run_test! do |response| expect([200, 403]).to
include(response.status) end end) and apply one of the two fixes to ensure
Swagger docs reflect both outcomes or the test matches the documented single
outcome.
- Around line 124-129: The test "participant not found returns null" currently
only asserts the HTTP status; update the example block around response '200'
that uses run_test! to also parse the response body (JSON.parse(response.body))
and assert the body is nil (expect(data).to be_nil) so the spec verifies the
described "null" behavior for a missing participant in the run_test! block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bffa4e7f-fcb4-46dd-81d6-fc376f4a90ff

📥 Commits

Reviewing files that changed from the base of the PR and between cc03ecd and ab08ded.

⛔ Files ignored due to path filters (8)
  • .DS_Store is excluded by !**/.DS_Store
  • app/.DS_Store is excluded by !**/.DS_Store
  • app/models/.DS_Store is excluded by !**/.DS_Store
  • app/views/.DS_Store is excluded by !**/.DS_Store
  • config/.DS_Store is excluded by !**/.DS_Store
  • spec/.DS_Store is excluded by !**/.DS_Store
  • spec/requests/.DS_Store is excluded by !**/.DS_Store
  • test/.DS_Store is excluded by !**/.DS_Store
📒 Files selected for processing (18)
  • .rubocop.yml
  • README.md
  • app/controllers/application_controller.rb
  • app/controllers/responses_controller.rb
  • app/controllers/student_tasks_controller.rb
  • app/models/assignment.rb
  • app/models/student_task.rb
  • app/models/task_ordering/base_task.rb
  • app/models/task_ordering/quiz_task.rb
  • app/models/task_ordering/review_task.rb
  • app/models/task_ordering/task_factory.rb
  • app/models/task_ordering/task_queue.rb
  • config/database.yml
  • config/routes.rb
  • spec/models/task_ordering_spec.rb
  • spec/rails_helper.rb
  • spec/requests/api/v1/responses_controller_spec.rb
  • spec/requests/api/v1/student_tasks_controller_spec.rb

Comment on lines +12 to +13
prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create] # changed from prepend_before_action

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify set_response and find_and_authorize_map_for_create are only defined in ResponsesController
echo "=== Checking where set_response is defined ==="
rg -n "def set_response" app/controllers/

echo "=== Checking where find_and_authorize_map_for_create is defined ==="
rg -n "def find_and_authorize_map_for_create" app/controllers/

echo "=== List all controllers that would be affected ==="
fd -e rb . app/controllers/ | wc -l

Repository: expertiza/reimplementation-back-end

Length of output: 394


🏁 Script executed:

#!/bin/bash
# Check the actual content of application_controller.rb around lines 12-13
echo "=== Content of application_controller.rb ==="
cat -n app/controllers/application_controller.rb | head -20

echo -e "\n=== Verify these methods don't exist in any other controller ==="
echo "Checking all controller files for set_response or find_and_authorize_map_for_create:"
rg -l "def set_response|def find_and_authorize_map_for_create" app/controllers/

echo -e "\n=== Check if ResponsesController only_calls these callbacks or defines them ==="
rg -B 2 -A 5 "def set_response" app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 1272


Critical: These callbacks are not defined in ApplicationController and will break other controllers.

set_response and find_and_authorize_map_for_create are defined only in ResponsesController (line 64 and 69 respectively). Adding these callbacks to ApplicationController will cause NoMethodError for every other controller's show, update, and create actions.

Move these callbacks to ResponsesController only:

Proposed fix

Remove from ApplicationController:

-  prepend_before_action :set_response, only: %i[show update]
-  before_action :find_and_authorize_map_for_create, only: %i[create]

Add to ResponsesController:

prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create] # changed from prepend_before_action
🧰 Tools
🪛 RuboCop (1.86.1)

[convention] 13-13: Unnecessary spacing detected.

(Layout/ExtraSpacing)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/application_controller.rb` around lines 12 - 13, The new
callbacks prepend_before_action :set_response and before_action
:find_and_authorize_map_for_create were added to ApplicationController but the
methods set_response and find_and_authorize_map_for_create are defined only in
ResponsesController and will raise NoMethodError in other controllers; remove
those two callback lines from ApplicationController and instead add them inside
ResponsesController (use prepend_before_action :set_response, only: %i[show
update] and before_action :find_and_authorize_map_for_create, only: %i[create])
so the callbacks live with the methods they call.

Comment on lines +3 to +5
class ResponsesController < ApplicationController
prepend_before_action :set_response, only: %i[show update]
before_action :find_and_authorize_map_for_create, only: %i[create]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify ApplicationController callback definitions
rg -n "before_action.*set_response|before_action.*find_and_authorize" app/controllers/application_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 253


Remove duplicate callback definitions inherited from ApplicationController.

ApplicationController already defines these callbacks (lines 12-13). Since ResponsesController extends it, redefining them here is redundant and may cause callbacks to execute in unexpected order or multiple times.

Delete lines 3-4 and rely on the inherited definitions from the parent class.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/responses_controller.rb` around lines 3 - 5, Remove the
duplicate before_action callbacks in ResponsesController: delete the
prepend_before_action :set_response, only: %i[show update] and before_action
:find_and_authorize_map_for_create, only: %i[create] lines so the controller
relies on the inherited callbacks defined in ApplicationController; ensure no
other local callback definitions remain that would reintroduce duplication for
set_response or find_and_authorize_map_for_create.

Comment on lines +32 to +34
response = Response.where(map_id: @map.id, round: round)
.order(:created_at)
.last || Response.new(map_id: @map.id, round: round)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Potential race condition in response selection/creation.

The pattern of where(...).last || new(...) followed by save isn't atomic. Under concurrent requests, two processes could both find no existing response, both create new ones, and save duplicates.

Consider using find_or_create_by with a unique constraint or locking:

♻️ Suggested fix
-    response = Response.where(map_id: `@map.id`, round: round)
-                       .order(:created_at)
-                       .last || Response.new(map_id: `@map.id`, round: round)
+    response = Response.find_or_initialize_by(map_id: `@map.id`, round: round)

Or with database-level uniqueness constraint on (map_id, round).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
response = Response.where(map_id: @map.id, round: round)
.order(:created_at)
.last || Response.new(map_id: @map.id, round: round)
response = Response.find_or_initialize_by(map_id: `@map.id`, round: round)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/responses_controller.rb` around lines 32 - 34, Replace the
non-atomic selection/creation pattern around Response (the
`Response.where(map_id: `@map.id`, round: round).order(:created_at).last ||
Response.new(...)` block) with an atomic find-or-create operation (e.g., use
Response.find_or_create_by(map_id: `@map.id`, round: round) or a transaction with
locking) and add/ensure a database-level unique constraint on (map_id, round) to
prevent duplicates; update any save/error handling around the Response creation
to handle uniqueness validation failures or ActiveRecord::RecordNotUnique
exceptions accordingly.

Comment on lines +76 to +78
unless @map.reviewer.user_id == current_user.id
render json: { error: "You are not authorized to create this responses" }, status: :forbidden
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Typo in error message.

"this responses" should be "this response".

-      render json: { error: "You are not authorized to create this responses" }, status: :forbidden
+      render json: { error: "You are not authorized to create this response" }, status: :forbidden
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
unless @map.reviewer.user_id == current_user.id
render json: { error: "You are not authorized to create this responses" }, status: :forbidden
end
unless `@map.reviewer.user_id` == current_user.id
render json: { error: "You are not authorized to create this response" }, status: :forbidden
end
🧰 Tools
🪛 RuboCop (1.86.1)

[convention] 76-76: Use a guard clause (return if @map.reviewer.user_id == current_user.id) instead of wrapping the code inside a conditional expression.

(Style/GuardClause)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/responses_controller.rb` around lines 76 - 78, Fix the typo
in the error message inside ResponsesController where the unauthorized branch
renders { error: "You are not authorized to create this responses" } — change
the string to "You are not authorized to create this response" so the grammar is
correct (look for the render json call in the unauthorized check using
`@map.reviewer.user_id` and current_user.id).

Comment on lines +69 to +110
class BaseTaskItem
attr_reader :assignment, :team_participant, :review_map

def initialize(assignment:, team_participant:, review_map:)
@assignment = assignment
@team_participant = team_participant
@review_map = review_map
end

def participant
team_participant.participant
end

def ensure_response!
map = response_map
return nil unless map
Response.find_or_create_by!(map_id: map.id, round: 1) do |r|
r.is_submitted = false
end
end

def completed?
map = response_map
return false unless map
Response.exists?(map_id: map.id, round: 1, is_submitted: true)
end

def to_h
map = response_map
{
task_type: task_type,
assignment_id: assignment.id,
response_map_id: map&.id,
response_map_type: map&.class&.name,
reviewee_id: map&.reviewee_id,
team_participant_id: team_participant.id
}
end

# Alias so existing code using to_task_hash still works
alias to_task_hash to_h
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Duplication with TaskOrdering::BaseTask.

BaseTaskItem duplicates most of the logic from TaskOrdering::BaseTask (lines 4-61 of app/models/task_ordering/base_task.rb): same ensure_response!, completed?, and serialization methods.

Consider either:

  1. Removing one in favor of the other
  2. Having BaseTaskItem inherit from TaskOrdering::BaseTask
  3. Extracting shared behavior into a module
🧰 Tools
🪛 RuboCop (1.86.1)

[convention] 84-84: Add empty line after guard clause.

(Layout/EmptyLineAfterGuardClause)


[convention] 92-92: Add empty line after guard clause.

(Layout/EmptyLineAfterGuardClause)


[convention] 99-99: Align the keys of a hash literal if they span more than one line.

(Layout/HashAlignment)


[convention] 100-100: Align the keys of a hash literal if they span more than one line.

(Layout/HashAlignment)


[convention] 101-101: Align the keys of a hash literal if they span more than one line.

(Layout/HashAlignment)


[convention] 102-102: Align the keys of a hash literal if they span more than one line.

(Layout/HashAlignment)


[convention] 103-103: Align the keys of a hash literal if they span more than one line.

(Layout/HashAlignment)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/controllers/student_tasks_controller.rb` around lines 69 - 110,
BaseTaskItem duplicates logic from TaskOrdering::BaseTask (ensure_response!,
completed?, to_h/to_task_hash); refactor by removing duplication: either make
BaseTaskItem inherit from TaskOrdering::BaseTask, or extract the shared methods
(ensure_response!, completed?, to_h/alias to_task_hash and any helpers like
participant/response_map usage) into a module (e.g., TaskItemShared) and include
it in both classes; update references to response_map/participant methods if
moved to keep behavior identical and run tests to ensure no behavior change.

Comment on lines +17 to +21
existing = QuizResponseMap.find_by(
reviewer_id: team_participant.participant_id,
reviewee_id: review_map&.reviewee_id || 0
)
return @response_map = existing if existing

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Using 0 as a fallback for reviewee_id may cause data integrity issues.

When review_map is nil, reviewee_id defaults to 0. This is not a valid foreign key reference and could:

  1. Create orphaned records that don't reference a real reviewee
  2. Cause incorrect lookups when multiple tasks have reviewee_id = 0

Consider either raising an error when review_map is nil, or using nil and updating the query to handle it explicitly.

🛡️ Suggested approach
-      existing = QuizResponseMap.find_by(
-        reviewer_id: team_participant.participant_id,
-        reviewee_id: review_map&.reviewee_id || 0
-      )
+      return nil unless review_map&.reviewee_id
+
+      existing = QuizResponseMap.find_by(
+        reviewer_id: team_participant.participant_id,
+        reviewee_id: review_map.reviewee_id
+      )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
existing = QuizResponseMap.find_by(
reviewer_id: team_participant.participant_id,
reviewee_id: review_map&.reviewee_id || 0
)
return @response_map = existing if existing
return nil unless review_map&.reviewee_id
existing = QuizResponseMap.find_by(
reviewer_id: team_participant.participant_id,
reviewee_id: review_map.reviewee_id
)
return `@response_map` = existing if existing
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/models/task_ordering/quiz_task.rb` around lines 17 - 21, The current code
uses 0 as a fallback for reviewee_id in QuizResponseMap.find_by, which is
invalid; update the logic to stop using 0: either (A) explicitly require
review_map and raise a clear error when review_map is nil (e.g. check review_map
and raise ArgumentError or return early) before calling
QuizResponseMap.find_by(reviewer_id: team_participant.participant_id,
reviewee_id: review_map.reviewee_id), or (B) let review_map&.reviewee_id return
nil and change the lookup to handle nil explicitly (use where(reviewer_id: ...,
reviewee_id: review_map&.reviewee_id).take with separate handling when
review_map is nil to avoid matching unintended NULL rows); reference
QuizResponseMap.find_by, team_participant.participant_id, and review_map to
locate the code and implement one of these fixes.

type: "QuizResponseMap"
}

@response_map = QuizResponseMap.new(attrs).tap { |m| m.save!(validate: false) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Bypassing validations with save!(validate: false) may persist invalid data.

Using validate: false skips model validations, which could allow invalid QuizResponseMap records to be saved. If validations are being bypassed intentionally to avoid specific checks, consider using conditional validation or save! without the flag after ensuring the data is valid.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/models/task_ordering/quiz_task.rb` at line 33, The current code creates a
QuizResponseMap with `@response_map` = QuizResponseMap.new(attrs).tap { |m|
m.save!(validate: false) } which bypasses model validations; change this to
ensure validations run by removing the validate: false flag and either validate
before saving or use conditional/explicit validations on QuizResponseMap to
permit these attrs. Specifically, update the creation flow for QuizResponseMap
so you build the record (QuizResponseMap.new(attrs)), call valid? (or handle
model.errors) and then call save! without validate: false, or refactor the model
validations (using conditional validators) so the record can be saved validly
when this path is used.

Comment thread config/database.yml
Comment on lines 12 to +14
test:
<<: *default
url: <%= ENV['DATABASE_URL'].gsub('?', '_test?') %>

production:
<<: *default
url: <%= ENV['DATABASE_URL'].gsub('?', '_production?') %> No newline at end of file
database: reimplementation_back_end_test

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if production config exists elsewhere or if there's documentation about production DB setup
rg -l "production" --type yaml -g "*.yml" | head -20
cat config/database.yml

Repository: expertiza/reimplementation-back-end

Length of output: 410


🏁 Script executed:

cat config/cable.yml

Repository: expertiza/reimplementation-back-end

Length of output: 276


🏁 Script executed:

# Check for any Rails configuration documentation or setup files
find . -type f \( -name "README*" -o -name "*.md" \) | xargs grep -l "production\|database" 2>/dev/null | head -10

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Check if there's a secrets.yml or other config mechanism for production
find config -type f | head -20

Repository: expertiza/reimplementation-back-end

Length of output: 589


🏁 Script executed:

cat config/database.yml.old

Repository: expertiza/reimplementation-back-end

Length of output: 1982


🏁 Script executed:

cat config/environments/production.rb

Repository: expertiza/reimplementation-back-end

Length of output: 3768


🏁 Script executed:

# Check if database.yml references environment variables or has comments about production
head -30 config/database.yml

Repository: expertiza/reimplementation-back-end

Length of output: 393


Restore production database configuration or document the production database setup strategy.

The production database configuration block has been removed from config/database.yml (it existed in database.yml.old). There is no corresponding database configuration in config/environments/production.rb, and no explicit environment variable configuration for production in the current database.yml. This will cause database connection failures in production unless the database configuration is provided entirely through a DATABASE_URL environment variable—which should be explicitly documented if intentional. The development configuration now uses environment variables (ENV['DATABASE_URL']), but the production block is completely absent rather than following the same pattern.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/database.yml` around lines 12 - 14, Restore a production database
configuration block in database.yml (or explicitly document using DATABASE_URL)
so production won't fail; add a production: entry that mirrors the development
pattern by reading ENV['DATABASE_URL'] (or the specific
adapter/host/name/username/password keys used previously), or update
config/environments/production.rb to load the same ENV variable; reference the
missing production block in database.yml and the ENV['DATABASE_URL'] usage in
development to ensure consistency and explicit behavior for production
deployments.

Comment thread config/database.yml
production:
<<: *default
url: <%= ENV['DATABASE_URL'].gsub('?', '_production?') %> No newline at end of file
database: reimplementation_back_end_test

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Database name mismatch between database.yml and rails_helper.rb.

The test database is configured as reimplementation_back_end_test here, but spec/rails_helper.rb (Line 16) sets DATABASE_URL to use reimplementation_test. This inconsistency may cause tests to connect to a different database than expected.

Ensure both files reference the same database name.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@config/database.yml` at line 14, The test DB names are inconsistent:
database.yml sets database: reimplementation_back_end_test while spec's
ENV['DATABASE_URL'] uses reimplementation_test; make them identical. Update
either the database key in database.yml (database: reimplementation_test) or
change the DATABASE_URL construction in spec/rails_helper.rb to reference
reimplementation_back_end_test so both the database.yml "database" value and the
ENV['DATABASE_URL'] string match exactly.

Comment on lines +137 to +146
before do
allow(assignment).to receive(:quiz_questionnaire_for_review_flow).and_return(questionnaire)
quiz_map = QuizResponseMap.new(
reviewer_id: reviewer_participant.id,
reviewee_id: reviewee_participant.id,
reviewed_object_id: assignment.id
)
quiz_map.save!(validate: false)
Response.create!(map_id: quiz_map.id, round: 1, is_submitted: true)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify how the controller loads the assignment
rg -n "quiz_questionnaire_for_review_flow" app/controllers/responses_controller.rb app/models/task_ordering/

Repository: expertiza/reimplementation-back-end

Length of output: 289


🏁 Script executed:

# First, check the responses_controller.rb file
wc -l app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 123


🏁 Script executed:

# Read the responses_controller.rb
head -100 app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 3123


🏁 Script executed:

# Check the test file context around lines 137-146
sed -n '120,180p' spec/requests/api/v1/responses_controller_spec.rb

Repository: expertiza/reimplementation-back-end

Length of output: 2227


🏁 Script executed:

# Search for task_factory and quiz_task usage in the codebase
rg -n "task_factory\|quiz_task" app/controllers/responses_controller.rb spec/requests/api/v1/responses_controller_spec.rb

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Read the rest of responses_controller.rb (lines 100-114)
tail -20 app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 777


🏁 Script executed:

# Search for TaskFactory, TaskOrdering, or task_ordering usage in the codebase
rg -n "TaskFactory\|TaskOrdering\|task_ordering" app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Check how assignment is defined in the test file
sed -n '1,130p' spec/requests/api/v1/responses_controller_spec.rb | grep -n "let.*assignment\|assignment ="

Repository: expertiza/reimplementation-back-end

Length of output: 105


🏁 Script executed:

# Check if enforce_task_order! uses assignment or loads it fresh
rg -B5 -A15 "def enforce_task_order!" app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 846


🏁 Script executed:

# Check TaskOrdering::TaskQueue to see how it uses assignment
cat -n app/models/task_ordering/task_queue.rb

Repository: expertiza/reimplementation-back-end

Length of output: 1613


🏁 Script executed:

# Check if prior_tasks_complete_for? accesses quiz_questionnaire_for_review_flow
rg -B5 -A20 "prior_tasks_complete_for" app/models/task_ordering/

Repository: expertiza/reimplementation-back-end

Length of output: 917


🏁 Script executed:

# Check the full test setup to understand assignment persistence
sed -n '30,150p' spec/requests/api/v1/responses_controller_spec.rb

Repository: expertiza/reimplementation-back-end

Length of output: 3341


🏁 Script executed:

# Check TaskFactory.build to see how it uses assignment and if it calls quiz_questionnaire_for_review_flow
cat -n app/models/task_ordering/task_factory.rb

Repository: expertiza/reimplementation-back-end

Length of output: 2571


🏁 Script executed:

# Check quiz_task.rb to confirm quiz_questionnaire_for_review_flow is called there
cat -n app/models/task_ordering/quiz_task.rb

Repository: expertiza/reimplementation-back-end

Length of output: 1322


🏁 Script executed:

# Verify that participant.assignment loads a fresh instance from DB
rg -B3 -A3 "class AssignmentParticipant" app/models/assignment_participant.rb | head -30

Repository: expertiza/reimplementation-back-end

Length of output: 347


🏁 Script executed:

# Check AssignmentParticipant model for assignment association
rg -A10 "class AssignmentParticipant" app/models/assignment_participant.rb | head -20

Repository: expertiza/reimplementation-back-end

Length of output: 598


🏁 Script executed:

# Verify participant.assignment loads from database (check belongs_to relationship)
grep -n "belongs_to.*assignment\|has_many.*participant" app/models/assignment_participant.rb app/models/assignment.rb | head -20

Repository: expertiza/reimplementation-back-end

Length of output: 408


🏁 Script executed:

# Confirm the flow: when test calls create endpoint, does it use the let(:assignment) or load fresh?
# Check if there's any way the test assignment gets reloaded
rg -n "reload\|refresh" spec/requests/api/v1/responses_controller_spec.rb

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Check if Assignment has an association method that returns the parent (self) or loads from DB
rg -A20 "def assignment" app/models/participant.rb app/models/assignment_participant.rb

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Verify the parent_id relationship more clearly
rg -n "parent_id\|parent_type" app/models/participant.rb app/models/assignment_participant.rb | head -20

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Check the Participant model for assignment method/association
cat -n app/models/participant.rb | head -50

Repository: expertiza/reimplementation-back-end

Length of output: 1222


🏁 Script executed:

# Search for how assignment is accessed from participant (polymorphic parent)
rg -B5 -A5 "parent.*assignment\|assignment.*parent" app/models/participant.rb

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Verify that participant.assignment reloads from DB or is cached
rg -n "assignment" app/models/participant.rb

Repository: expertiza/reimplementation-back-end

Length of output: 201


🏁 Script executed:

# Final verification: confirm TaskFactory is indeed called during the test
rg -n "TaskFactory\|TaskOrdering::TaskQueue" app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 61


🏁 Script executed:

# Double-check: TaskOrdering::TaskQueue is used in enforce_task_order!, verify this
grep -n "TaskOrdering" app/controllers/responses_controller.rb

Repository: expertiza/reimplementation-back-end

Length of output: 165


Stub on assignment may not affect controller's database-loaded instance.

The stub allow(assignment).to receive(:quiz_questionnaire_for_review_flow) is applied to the test's assignment object, but the controller loads a fresh Assignment instance from the database via participant.assignment (a belongs_to association). TaskOrdering::TaskQueue receives this fresh instance, passes it to TaskFactory.build, which then calls quiz_questionnaire_for_review_flow on it. Since the database-loaded instance is a different Ruby object than the stubbed one, the stub won't take effect.

Consider stubbing at the class level or persisting the questionnaire association:

♻️ Suggested approach
before do
  allow_any_instance_of(Assignment).to receive(:quiz_questionnaire_for_review_flow).and_return(questionnaire)
  # ... rest of setup
end

Or add the questionnaire association to the assignment in the database instead of stubbing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/requests/api/v1/responses_controller_spec.rb` around lines 137 - 146,
The stub on the local assignment object won't affect the Assignment instance the
controller loads via participant.assignment (used by TaskOrdering::TaskQueue →
TaskFactory.build), so replace the per-object stub with a class-level or
persisted approach: either use an any-instance stub for Assignment (so
quiz_questionnaire_for_review_flow is intercepted on the DB-loaded instance) or
attach the questionnaire to the assignment record in the database so the real
assignment instance returns the desired questionnaire when TaskFactory.build
calls quiz_questionnaire_for_review_flow.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Dangerfile (1)

28-29: Fix RuboCop “Extra blank line” in Dangerfile.

This added blank line (Lines 28-29) looks like it’s triggering RuboCop Layout/EmptyLines (“Extra blank line detected.”). If CI runs RuboCop, revert this formatting change to keep the file compliant.

♻️ Proposed fix
- 
 # --- Missing Test Checks ---
 warn("There are no test changes in this PR.") if (git.modified_files + git.added_files).none? { |f| f.include?('spec/') || f.include?('test/') }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dangerfile` around lines 28 - 29, The Dangerfile contains an unnecessary
blank line around the section header "# --- Missing Test Checks ---" that
triggers RuboCop Layout/EmptyLines; remove the extra empty line so the header is
directly adjacent to the surrounding content (i.e., collapse the two consecutive
newlines into a single newline) to restore RuboCop compliance while leaving the
header text unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Dangerfile`:
- Around line 28-29: The Dangerfile contains an unnecessary blank line around
the section header "# --- Missing Test Checks ---" that triggers RuboCop
Layout/EmptyLines; remove the extra empty line so the header is directly
adjacent to the surrounding content (i.e., collapse the two consecutive newlines
into a single newline) to restore RuboCop compliance while leaving the header
text unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fe5255f7-681f-4524-bc51-12ed7a3d0473

📥 Commits

Reviewing files that changed from the base of the PR and between ab08ded and 77f2e4e.

⛔ Files ignored due to path filters (1)
  • .DS_Store is excluded by !**/.DS_Store
📒 Files selected for processing (1)
  • Dangerfile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Dangerfile (1)

3-11: Narrow safe_read exception handling and remove the pre-check race.

File.exist? + File.open introduces a TOCTOU gap, and bare rescue hides unexpected failures. Read directly and rescue only expected file/encoding errors.

Proposed patch
 def safe_read(path)
-  return "" unless File.exist?(path)
-
-  File.open(path, "rb") do |f|
-    f.read
-     .force_encoding("UTF-8")
-     .encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
-  end
-rescue
+  File.binread(path)
+      .force_encoding("UTF-8")
+      .encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
+rescue Errno::ENOENT, Errno::EACCES, Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError
   ""
 end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dangerfile` around lines 3 - 11, The current safe_read implementation uses
File.exist? before File.open (TOCTOU) and a bare rescue; change it to read
directly (e.g., File.binread or File.read with "rb") and perform the encoding
steps on that content, and replace the broad rescue with rescues for expected
errors (Errno::ENOENT, Errno::EACCES, Encoding::InvalidByteSequenceError,
Encoding::UndefinedConversionError) returning "" in those cases; update the
function referenced as safe_read to remove the pre-check and only catch those
specific exceptions so other errors bubble up.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Dangerfile`:
- Around line 3-11: The current safe_read implementation uses File.exist? before
File.open (TOCTOU) and a bare rescue; change it to read directly (e.g.,
File.binread or File.read with "rb") and perform the encoding steps on that
content, and replace the broad rescue with rescues for expected errors
(Errno::ENOENT, Errno::EACCES, Encoding::InvalidByteSequenceError,
Encoding::UndefinedConversionError) returning "" in those cases; update the
function referenced as safe_read to remove the pre-check and only catch those
specific exceptions so other errors bubble up.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d5491945-dd56-467e-a5cf-d84cd0f89f2a

📥 Commits

Reviewing files that changed from the base of the PR and between 77f2e4e and 02a1c56.

📒 Files selected for processing (1)
  • Dangerfile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants