Skip to content

feat(imports): validate Sure NDJSON before publish#1833

Open
JSONbored wants to merge 7 commits into
we-promise:mainfrom
JSONbored:codex/import-preflight-readiness
Open

feat(imports): validate Sure NDJSON before publish#1833
JSONbored wants to merge 7 commits into
we-promise:mainfrom
JSONbored:codex/import-preflight-readiness

Conversation

@JSONbored
Copy link
Copy Markdown
Contributor

@JSONbored JSONbored commented May 19, 2026

Summary

  • Add strict Sure NDJSON preflight checks before publish or enqueue.
  • Surface concrete import failure messages on the failure page and API responses.
  • Document that strict reference validation is package-scoped, not incremental against existing family records.

What changed

  • Added a Sure import preflight checker for taxonomy collisions, missing fields, invalid accountables, missing references, duplicate valuations, duplicate taxonomy names, and unsupported record types.
  • Added explicit taxonomy merge mode through import options, defaulting to strict behavior.
  • Updated the importer to reuse existing category, tag, and merchant rows only when merge mode is explicitly enabled.
  • Kept reference validation strict by requiring referenced account, parent category, budget, transaction, and related IDs to appear in the same NDJSON package.
  • Expanded import/export route coverage for supported Sure NDJSON records, including split-line and transfer-related paths.
  • Updated API preflight/create behavior, OpenAPI docs, and tests.

Why

  • Dirty self-hosted import targets should fail before mutation with specific blocking errors instead of a generic failed import screen.
  • Strict default behavior keeps full-package import certification from silently hiding taxonomy drift.
  • Incremental imports that build on existing family records should be a separate explicit mode rather than a quiet change to strict preflight semantics.

Validation

  • bin/rails test test/models/sure_import_test.rb test/models/family/data_importer_test.rb test/models/import/preflight_test.rb test/controllers/api/v1/imports_controller_test.rb test/views/imports/failure_view_test.rb
  • RAILS_ENV=test bundle exec rake rswag:specs:swaggerize
  • bin/rubocop
  • bundle exec erb_lint app/views/imports/_failure.html.erb
  • bin/rails zeitwerk:check
  • bundle exec brakeman -q -f json
  • git diff --check
  • Follow-up validation for the package-scoped reference clarification:
    • bin/rails test test/models/sure_import_test.rb
    • RAILS_ENV=test bundle exec rake rswag:specs:swaggerize
    • bin/rubocop app/models/sure_import/preflight.rb test/models/sure_import_test.rb spec/requests/api/v1/imports_spec.rb
    • git diff --check
    • CodeRabbit CLI review on the uncommitted diff: 0 findings.
    • Codex Security diff scan: no reportable issues found.

Notes

  • Draft PR for review and CI feedback.
  • Screenshots are not included because the only UI change is the existing import failure partial rendering server-side error details, covered by view tests.

Summary by CodeRabbit

  • New Features

    • Native split-transaction import/export and an import option to merge existing taxonomy; import options are now persisted.
  • Bug Fixes

    • Stronger preflight validation with dedicated preflight-failure responses (includes import ID) and preserved import state when auto-publish fails.
    • Configurable NDJSON file-size and row limits with clearer oversize/invalid upload handling.
  • UI Improvements

    • Import failure view shows detailed error lines and improved alert styling.
  • Documentation

    • API docs and endpoints accept a merge_existing_taxonomy flag for imports and preflight.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds SureImport NDJSON preflight validation, a persisted merge_existing_taxonomy import option, split-line import/export support, env-configurable size/row limits, API error handling for preflight/max-row failures, OpenAPI updates, and extensive tests.

Changes

Split Transactions & Taxonomy Merging Import Feature

Layer / File(s) Summary
Database schema & migration
db/migrate/20260518170000_add_import_options_to_imports.rb, db/schema.rb
Adds import_options JSONB column to imports and updates schema version.
SureImport limits, errors & publish flow
app/models/sure_import.rb
Introduce NotPublishableError/PreflightError, env-based max_ndjson_size/max_row_count, merge_existing_taxonomy accessors persisted in import_options, publish_later/publish with preflight and status handling.
SureImport::Preflight validator
app/models/sure_import/preflight.rb
New NDJSON preflight validator: parse records, per-type grouping, required-field validation, taxonomy collision detection, duplicate-name detection, accountable subtype checks, strict cross-record reference validation (including split_lines/tag_ids), duplicate valuation detection, and Result struct with stats/errors/warnings.
Import::Preflight delegation & param wiring
app/models/import/preflight.rb
Add :merge_existing_taxonomy to allowed params and delegate sure-import preflight processing to SureImport::Preflight, using its Result for stats/errors/warnings.
API controllers: merge option wiring & error handling
app/controllers/api/v1/imports_controller.rb, app/controllers/import/uploads_controller.rb, app/controllers/imports_controller.rb
Persist merge_existing_taxonomy into import options when present; update NDJSON size checks to SureImport.max_ndjson_size; handle SureImport::PreflightError and Import::MaxRowCountExceededError with dedicated JSON responses/alerts.
Family::DataImporter taxonomy merge & split-line import
app/models/family/data_importer.rb
initialize accepts merge_existing_taxonomy:; optionally reuse existing categories/tags/merchants by name; track created category IDs for parent updates; implement split-line detection and child-entry import with per-split metadata and tag handling; centralize opening-balance skip logic.
Family::DataExporter split-line export
app/models/family/data_exporter.rb
Export parent transactions via ndjson_exportable_transactions and include optional split_lines serialized from child entries when present.
API docs & request specs
docs/api/openapi.yaml, spec/requests/api/v1/imports_spec.rb
Add merge_existing_taxonomy boolean to POST /api/v1/imports and POST /api/v1/imports/preflight request schemas (JSON + multipart); align request specs and failing-enqueue test payloads.
Tests & failure partial
test/models/*, test/controllers/*, test/views/*, app/views/imports/_failure.html.erb
Add/extend tests for preflight collisions/merge mode, publish/publish_later blocking, split-line import/export, importer/exporter behavior, SureImport env-limit tests, and view test; failure partial now lists import.error lines.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant API as ImportsController
  participant Preflight as SureImport::Preflight
  participant Importer as SureImport
  participant Background as ImportJob
  Client->>API: POST /imports (NDJSON + merge_existing_taxonomy?)
  API->>Preflight: SureImport::Preflight.new(family:, content:, merge_existing_taxonomy:).call
  Preflight-->>API: Result (valid?, stats, errors, warnings)
  API->>Importer: create import record (persist merge flag)
  alt publish requested
    API->>Importer: publish_later (runs validate_sure_preflight!)
    Importer->>Background: ImportJob.perform_later(import)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

pr:verified

Suggested reviewers

  • jjmata
  • sokie

Poem

🐇 I hopped through NDJSON lines so neat,
split-lines nested, tidy and complete,
preflight checked each name and id,
merge flags let old taxonomies slide,
now imports queue and families sleep.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat(imports): validate Sure NDJSON before publish' directly and clearly summarizes the main change—adding validation of Sure NDJSON files before publishing imports.
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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Collaborator

jjmata commented May 19, 2026

The preflight design is solid and the test coverage is thorough. One structural limitation worth flagging before merge:

Reference validation only checks NDJSON source IDs, not existing family records
validate_references resolves all references against @source_ids, which is populated only from records inside the NDJSON file. This means a partial/incremental import — e.g., importing only Balance, Trade, or Valuation records that reference accounts already present in the family — will fail preflight with missing_reference errors even though the accounts exist.

The same applies to Category#parent_id: a category with an existing family category as its parent will be rejected.

For the strict "full package" import case this is intentional and correct. But it means the preflight gate is currently incompatible with any incremental or additive NDJSON that builds on the existing family state. The PR description hints at this being intentional ("strict default"), but it's worth making the limitation explicit in a comment on validate_references (or in the API docs), since callers might not expect a valid account_id to be rejected just because it wasn't in the same file.

If incremental imports are a future goal, the fix would be to seed @source_ids with existing family record IDs before parsing — but that changes the semantics of strict mode, so it probably warrants a separate option rather than a quiet behavior change.


Generated by Claude Code

@JSONbored JSONbored marked this pull request as ready for review May 19, 2026 06:48
@superagent-security superagent-security Bot added contributor:verified Contributor passed trust analysis. pr:verified PR passed security analysis. labels May 19, 2026
@JSONbored
Copy link
Copy Markdown
Contributor Author

The preflight design is solid and the test coverage is thorough. One structural limitation worth flagging before merge:

Reference validation only checks NDJSON source IDs, not existing family records validate_references resolves all references against @source_ids, which is populated only from records inside the NDJSON file. This means a partial/incremental import — e.g., importing only Balance, Trade, or Valuation records that reference accounts already present in the family — will fail preflight with missing_reference errors even though the accounts exist.

The same applies to Category#parent_id: a category with an existing family category as its parent will be rejected.

For the strict "full package" import case this is intentional and correct. But it means the preflight gate is currently incompatible with any incremental or additive NDJSON that builds on the existing family state. The PR description hints at this being intentional ("strict default"), but it's worth making the limitation explicit in a comment on validate_references (or in the API docs), since callers might not expect a valid account_id to be rejected just because it wasn't in the same file.

If incremental imports are a future goal, the fix would be to seed @source_ids with existing family record IDs before parsing — but that changes the semantics of strict mode, so it probably warrants a separate option rather than a quiet behavior change.

Generated by Claude Code

Addressed in e4bb70b.

I kept strict mode package-scoped rather than seeding @source_ids from existing family records, since that would change import semantics and should be a separate explicit incremental mode if/when we support it.

What changed:

So yes, this is now explicit in code, tested, and reflected in the generated API surface without quietly expanding strict mode into incremental import behavior.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/models/family/data_exporter.rb (1)

305-323: ⚡ Quick win

Potential N+1 queries when serializing split lines.

The includes on line 305 does not eager load child_entries or their associations. For each split parent, serialize_split_lines_for_export triggers separate queries for child_entries, their entryable, and potentially tag_ids.

♻️ Suggested fix to eager load child entries
-      ndjson_exportable_transactions.includes(:category, :merchant, :tags, entry: :account).find_each do |transaction|
+      ndjson_exportable_transactions.includes(:category, :merchant, :tags, entry: [:account, { child_entries: { entryable: :tags } }]).find_each do |transaction|
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/models/family/data_exporter.rb` around lines 305 - 323, The code is
causing N+1 queries because ndjson_exportable_transactions is not eager-loading
split child entries and their associations; update the query used in
ndjson_exportable_transactions/includes(...) to also preload entry.child_entries
and their entryable and tags (so that serialize_split_lines_for_export doesn’t
trigger per-transaction queries). Specifically, ensure the relation passed into
ndjson_exportable_transactions.includes includes nested associations like entry:
[:account, { child_entries: [:entryable, :tags] }] or equivalent so
serialize_split_lines_for_export, child_entries, entryable and tag_ids are
loaded up front.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/models/sure_import.rb`:
- Around line 154-156: Change the bare rescue in the SureImport exception
handling to only catch application-level errors: replace "rescue => error" with
"rescue StandardError => error" in the block that calls update! status: :failed,
error: error.message (the rescue around the SureImport import logic), so
SignalException/SystemExit aren't swallowed while preserving the existing
update! behavior.

---

Nitpick comments:
In `@app/models/family/data_exporter.rb`:
- Around line 305-323: The code is causing N+1 queries because
ndjson_exportable_transactions is not eager-loading split child entries and
their associations; update the query used in
ndjson_exportable_transactions/includes(...) to also preload entry.child_entries
and their entryable and tags (so that serialize_split_lines_for_export doesn’t
trigger per-transaction queries). Specifically, ensure the relation passed into
ndjson_exportable_transactions.includes includes nested associations like entry:
[:account, { child_entries: [:entryable, :tags] }] or equivalent so
serialize_split_lines_for_export, child_entries, entryable and tag_ids are
loaded up front.
🪄 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

Run ID: 4e345822-4081-42b5-b232-57759fa9c635

📥 Commits

Reviewing files that changed from the base of the PR and between bc9f130 and e4bb70b.

📒 Files selected for processing (19)
  • app/controllers/api/v1/imports_controller.rb
  • app/controllers/import/uploads_controller.rb
  • app/controllers/imports_controller.rb
  • app/models/family/data_exporter.rb
  • app/models/family/data_importer.rb
  • app/models/import/preflight.rb
  • app/models/sure_import.rb
  • app/models/sure_import/preflight.rb
  • app/views/imports/_failure.html.erb
  • db/migrate/20260518170000_add_import_options_to_imports.rb
  • db/schema.rb
  • docs/api/openapi.yaml
  • spec/requests/api/v1/imports_spec.rb
  • test/controllers/api/v1/imports_controller_test.rb
  • test/models/family/data_exporter_test.rb
  • test/models/family/data_importer_test.rb
  • test/models/import/preflight_test.rb
  • test/models/sure_import_test.rb
  • test/views/imports/failure_view_test.rb

Comment thread app/models/sure_import.rb Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e4bb70be7d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread app/models/family/data_importer.rb
Comment thread app/models/family/data_importer.rb Outdated
Comment thread app/models/family/data_importer.rb Outdated
@JSONbored JSONbored force-pushed the codex/import-preflight-readiness branch from 71b0793 to 5f8f3c9 Compare May 19, 2026 18:33
@superagent-security superagent-security Bot removed the pr:verified PR passed security analysis. label May 19, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
app/models/sure_import.rb (1)

133-142: 💤 Low value

Consider using a custom error class for consistency.

The method raises MaxRowCountExceededError and PreflightError for specific failure conditions, but line 137 raises a bare RuntimeError. For consistent error handling by callers, consider introducing a NotPublishableError or similar.

♻️ Suggested refactor
 class SureImport < Import
   PreflightError = Class.new(StandardError)
+  NotPublishableError = Class.new(StandardError)
-    raise "Import is not publishable" unless publishable?
+    raise NotPublishableError, "Import is not publishable" unless publishable?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/models/sure_import.rb` around lines 133 - 142, The publish_later method
raises a bare RuntimeError when the import is not publishable; replace that with
a custom error (e.g., NotPublishableError) so callers can handle it
consistently: add a new NotPublishableError class (parallel to
MaxRowCountExceededError/PreflightError) and change the raise "Import is not
publishable" in publish_later to raise NotPublishableError, keeping the existing
checks row_count_exceeded?, validate_sure_preflight!, and publishable? intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/models/sure_import.rb`:
- Around line 133-142: The publish_later method raises a bare RuntimeError when
the import is not publishable; replace that with a custom error (e.g.,
NotPublishableError) so callers can handle it consistently: add a new
NotPublishableError class (parallel to MaxRowCountExceededError/PreflightError)
and change the raise "Import is not publishable" in publish_later to raise
NotPublishableError, keeping the existing checks row_count_exceeded?,
validate_sure_preflight!, and publishable? intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 283211e2-ee1d-456b-8397-1822c92ac086

📥 Commits

Reviewing files that changed from the base of the PR and between 71b0793 and 5f8f3c9.

📒 Files selected for processing (19)
  • app/controllers/api/v1/imports_controller.rb
  • app/controllers/import/uploads_controller.rb
  • app/controllers/imports_controller.rb
  • app/models/family/data_exporter.rb
  • app/models/family/data_importer.rb
  • app/models/import/preflight.rb
  • app/models/sure_import.rb
  • app/models/sure_import/preflight.rb
  • app/views/imports/_failure.html.erb
  • db/migrate/20260518170000_add_import_options_to_imports.rb
  • db/schema.rb
  • docs/api/openapi.yaml
  • spec/requests/api/v1/imports_spec.rb
  • test/controllers/api/v1/imports_controller_test.rb
  • test/models/family/data_exporter_test.rb
  • test/models/family/data_importer_test.rb
  • test/models/import/preflight_test.rb
  • test/models/sure_import_test.rb
  • test/views/imports/failure_view_test.rb
✅ Files skipped from review due to trivial changes (3)
  • db/migrate/20260518170000_add_import_options_to_imports.rb
  • app/controllers/import/uploads_controller.rb
  • db/schema.rb
🚧 Files skipped from review as they are similar to previous changes (14)
  • app/controllers/imports_controller.rb
  • app/controllers/api/v1/imports_controller.rb
  • test/models/import/preflight_test.rb
  • test/models/family/data_exporter_test.rb
  • test/views/imports/failure_view_test.rb
  • spec/requests/api/v1/imports_spec.rb
  • app/models/import/preflight.rb
  • app/views/imports/_failure.html.erb
  • test/models/family/data_importer_test.rb
  • docs/api/openapi.yaml
  • test/models/sure_import_test.rb
  • app/models/family/data_importer.rb
  • test/controllers/api/v1/imports_controller_test.rb
  • app/models/family/data_exporter.rb

@JSONbored
Copy link
Copy Markdown
Contributor Author

Ready for maintainer review.

Addressed the CodeRabbit nitpick by replacing SureImport's generic publish_later RuntimeError with SureImport::NotPublishableError and added focused model coverage.

Current head 82ffbde has required CI green.

JSONbored added 6 commits May 20, 2026 18:15
Track split parent entries for Sure import revert, preserve explicit empty split-line taxonomy values, and eager-load split child data during NDJSON export.

Also narrows SureImport publish failure handling to StandardError and adds regression coverage for the reviewed paths.
@JSONbored JSONbored force-pushed the codex/import-preflight-readiness branch from 9ca9551 to c726e03 Compare May 21, 2026 02:08
@superagent-security superagent-security Bot added the pr:verified PR passed security analysis. label May 21, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/controllers/imports_controller.rb (1)

22-30: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rescue SureImport::NotPublishableError in web publish flow.

Line 23 can raise SureImport::NotPublishableError; it is not rescued here, so users can hit a 500 for a predictable validation condition.

Proposed fix
   def publish
     `@import.publish_later`

     redirect_to import_path(`@import`), notice: t(".started")
   rescue Import::MaxRowCountExceededError
     redirect_back_or_to import_path(`@import`), alert: t(".max_rows_exceeded", max: `@import.max_row_count`)
+  rescue SureImport::NotPublishableError => e
+    redirect_back_or_to import_path(`@import`), alert: e.message
   rescue SureImport::PreflightError => e
     redirect_to import_path(`@import`), alert: e.message
   end
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/controllers/imports_controller.rb` around lines 22 - 30, The publish
action can raise SureImport::NotPublishableError when calling
`@import.publish_later`; add a rescue clause for SureImport::NotPublishableError
in the publish method (alongside the existing SureImport::PreflightError rescue)
to handle this predictable validation failure by redirecting to
import_path(`@import`) (or redirect_back_or_to if preferred) and showing an
appropriate alert (use the exception message or a localized i18n key). Ensure
you reference the publish method and the exception class
SureImport::NotPublishableError when making the change.
🧹 Nitpick comments (1)
app/views/imports/_failure.html.erb (1)

15-21: ⚡ Quick win

Prefer DS::Alert over custom alert container markup.

This block is implementing design-system alert behavior manually; use the existing DS alert component for consistency and maintainability.

As per coding guidelines, "Check app/components/DS/ for existing design system components (DS::Alert, DS::Button, DS::Disclosure, DS::Dialog, DS::Menu, etc.) before writing custom component logic."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/views/imports/_failure.html.erb` around lines 15 - 21, Replace the custom
alert markup with the design-system component DS::Alert: remove the manual
div/list markup and render DS::Alert (from app/components/DS/) with the same
styling/intent (destructive variant) and move the existing iteration over
import.error.lines.map(&:strip).reject(&:blank?) into the DS::Alert body so each
message is rendered as a list item; ensure you use the DS::Alert API
(variant/role/heading slots if available) to preserve semantics and visual
behavior while keeping the iteration logic tied to the import object and the
same message filtering.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/controllers/api/v1/imports_controller.rb`:
- Around line 245-261: Add a specific rescue for SureImport::NotPublishableError
before the generic StandardError rescue so that when `@import.publish_later`
raises NotPublishableError it returns a 422 instead of falling through to 500;
render a JSON response matching the other error blocks (error:
"not_publishable", a helpful message like "Import was uploaded but has no
publishable records.", include import_id: `@import.id` and any relevant
`@import.error` details if available) and set status: :unprocessable_entity, then
return to stop further handling.

In `@app/models/sure_import.rb`:
- Around line 156-159: In publish_later, avoid leaving the record stuck in
:importing if ImportJob.perform_later(self) raises: capture the current status
(e.g., previous_status = status), call update! status: :importing, then wrap
ImportJob.perform_later(self) in a begin/rescue; on rescue update! status:
previous_status (or the appropriate fallback) and re-raise or propagate the
error so callers see the failure; optionally wrap the status change and enqueue
in a transaction if supported. Ensure you reference the update! status:
:importing line and the ImportJob.perform_later(self) call when making the
change.

---

Outside diff comments:
In `@app/controllers/imports_controller.rb`:
- Around line 22-30: The publish action can raise
SureImport::NotPublishableError when calling `@import.publish_later`; add a rescue
clause for SureImport::NotPublishableError in the publish method (alongside the
existing SureImport::PreflightError rescue) to handle this predictable
validation failure by redirecting to import_path(`@import`) (or
redirect_back_or_to if preferred) and showing an appropriate alert (use the
exception message or a localized i18n key). Ensure you reference the publish
method and the exception class SureImport::NotPublishableError when making the
change.

---

Nitpick comments:
In `@app/views/imports/_failure.html.erb`:
- Around line 15-21: Replace the custom alert markup with the design-system
component DS::Alert: remove the manual div/list markup and render DS::Alert
(from app/components/DS/) with the same styling/intent (destructive variant) and
move the existing iteration over
import.error.lines.map(&:strip).reject(&:blank?) into the DS::Alert body so each
message is rendered as a list item; ensure you use the DS::Alert API
(variant/role/heading slots if available) to preserve semantics and visual
behavior while keeping the iteration logic tied to the import object and the
same message filtering.
🪄 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

Run ID: 04177f49-0d8d-469e-9f8a-e3c44b4b037e

📥 Commits

Reviewing files that changed from the base of the PR and between 82ffbde and c726e03.

📒 Files selected for processing (19)
  • app/controllers/api/v1/imports_controller.rb
  • app/controllers/import/uploads_controller.rb
  • app/controllers/imports_controller.rb
  • app/models/family/data_exporter.rb
  • app/models/family/data_importer.rb
  • app/models/import/preflight.rb
  • app/models/sure_import.rb
  • app/models/sure_import/preflight.rb
  • app/views/imports/_failure.html.erb
  • db/migrate/20260518170000_add_import_options_to_imports.rb
  • db/schema.rb
  • docs/api/openapi.yaml
  • spec/requests/api/v1/imports_spec.rb
  • test/controllers/api/v1/imports_controller_test.rb
  • test/models/family/data_exporter_test.rb
  • test/models/family/data_importer_test.rb
  • test/models/import/preflight_test.rb
  • test/models/sure_import_test.rb
  • test/views/imports/failure_view_test.rb
✅ Files skipped from review due to trivial changes (1)
  • db/schema.rb

Comment thread app/controllers/api/v1/imports_controller.rb
Comment thread app/models/sure_import.rb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor:verified Contributor passed trust analysis. pr:verified PR passed security analysis.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants