Files
sure/lib/generators
markhainesandClaude Opus 5 5a0723bb84 fix(generators): stop provider:family emitting a broken migration and invalid enum (#3047)
* fix(generators): stop provider:family emitting a broken migration and invalid enum

Two bugs in the per-family provider generator, both of which stop the generated code
from running at all.

1. Duplicate migration columns. The items table already defines institution_id,
   institution_name, status and others, but any matching field passed on the command
   line was emitted a second time in the provider-specific block, so db:migrate aborted
   with "you can't define an already defined column". Reserved names are now filtered
   out of that block, with a notice, since the standard column serves the same purpose.

2. Invalid Ruby in the source enums. The patcher appended the new entry directly before
   the closing brace. In a multi-line hash the previous entry is followed by a newline,
   so the inserted text landed on its own line after Ruby had already ended the
   expression, producing:

       redbark: "redbark"
     , gocardless: "gocardless"}

   data_enrichment.rb then failed to parse, surfacing later as a confusing eager-load
   error rather than anything pointing at the generator. The comma is now attached to
   the final entry and the new entry indented to match its siblings. The single-line
   form used by provider_merchant.rb is preserved.

Found while adding a GoCardless provider; both reproduce with any invocation of
rails g provider:family.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(generators): add the syncable scope the family syncer requires

The generated item model includes Syncable, so Family::Syncer's reflective discovery
picks up the new `*_items` association and calls `syncable` on it. The template never
defined that scope, so a freshly generated provider raises

    NoMethodError: undefined method 'syncable' for an instance of
    ActiveRecord::Associations::CollectionProxy
    app/models/family/syncer.rb:38

and takes down the ENTIRE nightly family sync, not just the new provider. Every other
item model in the app defines `scope :syncable, -> { active }`; the template now does
the same.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(generators): emit valid i18n interpolation in the locale template

The locale template wrote %%{count} where I18n expects %{count}. Rails generator ERB
does not collapse %% (percent trim mode only applies to lines starting with %), so the
doubled percent reached the generated file verbatim and I18n rendered it as a literal
percent sign followed by the placeholder.

Every generated provider therefore displayed strings like

    %{count} accounts synced

instead of the count. 40 occurrences across sync status, institution summary, account
setup and error messages. Every hand-written locale in the app uses the single-percent
form.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(generators): reject reserved field names instead of silently dropping them

Addresses review feedback on the duplicate-column fix.

Filtering reserved names out of the migration alone was inconsistent: parsed_fields
also feeds the item model (validations, encryption), the settings panel (form inputs),
the controller params, the locale strings, the adapter and the SDK. A declared
institution_id:integer would therefore render a numeric form input and a presence
validation over the built-in string column. Declaring a reserved name is now a
Thor::Error naming the field and telling the user to drop it, which keeps the generated
code self-consistent and fails at generate time rather than at db:migrate.

Also removes 'family' from the reserved list. The migration writes
t.references :family, which creates family_id, so a field named family is not a
collision; family_id remains reserved.

Verified: institution_id is rejected with a useful message, family:string generates
cleanly, and an ordinary invocation is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(generators): do not double the comma when the source enum has a trailing one

Addresses review feedback. When the enum hash is written with a trailing comma, the
captured body already ends with a separator, so appending another produced

    redbark: "redbark",,
    gocardless: "gocardless"

which is the same class of syntax error the surrounding fix exists to prevent. The
separator is now chosen from whether the body already ends with a comma.

Extracts the transformation to Provider::FamilyGenerator.append_source_enum_entry, a
pure string operation, and adds regression tests covering single-line and multiline
enums with and without trailing commas. Each case asserts the result actually parses:
the failure mode here is a SyntaxError surfacing in an unrelated file with nothing
pointing back at the generator, so asserting on shape alone would be too weak.

Verified the tests fail without the fix (2 failures, both trailing-comma cases).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(generators): do not emit a leading comma into an empty source enum

Addresses review feedback. When the target has `enum :source, {}` the captured body is
empty, so the separator produced `enum :source, {, gocardless: "gocardless"}` and the
generated model failed to parse.

No separator is emitted when the body is empty. Adds regression tests for the empty
single-line and multiline forms, both asserting the result parses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 01:16:36 +02:00
..