thecore_generators
Part of the Thecore framework.
Rails-native generators for Thecore 3 apps and ATOMs — replacing the scaffolding logic
currently duplicated in the Thecore VS Code extension.
Wherever Rails already has a native generator command to override (rails generate model/migration), this gem hooks it instead of inventing new vocabulary; operations with
no Rails-native equivalent (ATOM creation, action scaffolding, app bootstrapping) get their
own thecore:*-namespaced generators or an application template. See
docs/adr/0002-thecore-generators-gem-and-generator-hook-mechanism.md
in the thecore repo for the full design.
Status: Model + Migration generator hook (Phase 1 of
ADR 0002).
ThecoreGenerators::Railtie registers config.app_generators.orm :thecore, migration: true, timestamps: true, so plain rails generate model/rails generate migration
transparently apply thecore's scaffolding conventions — no new command vocabulary.
What rails generate model/rails generate migration do now
-
Context-aware placement.
Thecore::Generators::WorkspaceContextdetects whether the invoking process'sDir.pwdis inside a host app or an ATOM (vendor/submodules/<atom>/, by gemspec presence — a Ruby port ofthecore_code_extension'sworkspaceContext.js). When an ATOM is detected, the model/migration/test files land inside that ATOM's ownapp/models/db/migrate/testinstead of the host app's. Pass--atom=NAMEto override detection explicitly (works independent ofcwd, e.g. from CI or the host-app root). -
No concern files by default.
Api::ModelName/RailsAdmin::ModelNameconcern files are not generated (per ADR 0001) — the no-customization case relies entirely on the defaultjson_attrs/navigation_label/navigation_iconbehavior thatmodel_driven_apiandthecore_ui_rails_adminincludeinto everyApplicationRecordsubclass automatically (ThecoreBackendCommons::DefaultModuleRegistry). Pass--with-api-concernand/or--with-admin-concernto scaffold a starter concern file — identical in shape to what this generator produced before this default changed — for the case where customization is already known to be needed at generation time:rails generate model Foo name:string --with-api-concern --with-admin-concernSee "Adding a concern by hand" below for the (more common) case of realizing customization is needed after the model already exists.
-
No
Endpoints::ModelNameby default (per ADR 0001) — add one by hand, following theafter_initialize+class_evalpattern, only when a real custom action is needed. -
Test file generation is never suppressed — a real Minitest file is generated, same as Rails' own
active_record:modeldefault. -
rails generate active_record:model/active_record:migrationstill work directly as an escape hatch, entirely unaffected by the hook above.
Both Thecore::Generators::ModelGenerator and MigrationGenerator wrap (not reimplement)
ActiveRecord::Generators::ModelGenerator/MigrationGenerator — all attribute parsing and
template content is inherited as-is; only file placement and the two opt-in concerns are
added on top.
Adding a concern by hand
The common case is not knowing at rails generate model time that a model will need
custom API serialization or RailsAdmin configuration — that need usually surfaces later.
Since neither concern is generated by default, add the missing one directly instead of
regenerating the model:
Api::ModelName (custom json_attrs) — create app/models/concerns/api/model_name.rb:
module Api::ModelName
extend ActiveSupport::Concern
included do
cattr_accessor :json_attrs
self.json_attrs = ::ModelDrivenApi.smart_merge(json_attrs || {}), { only: [:id, :name] }
end
end
then include Api::ModelName in the model. Because the default module (model_driven_api's
ModelDrivenApiDefaultJsonAttrs) is already included by the time the model class body
runs, ::ModelDrivenApi.smart_merge(json_attrs || {}, ...) composes on top of it rather
than starting from nothing — the same pattern the opt-in --with-api-concern template
below uses.
RailsAdmin::ModelName (custom admin config) — create
app/models/concerns/rails_admin/model_name.rb:
module RailsAdmin::ModelName
extend ActiveSupport::Concern
included do
rails_admin do
I18n.t('admin.registries.label')
'fa fa-file' # see https://fontawesome.com/v5/search
configure :some_field do
hide
end
end
end
end
then include RailsAdmin::ModelName in the model. RailsAdmin evaluates same-origin
rails_admin do ... end blocks in registration order and later calls win on settings they
touch (navigation_label/navigation_icon are last-write-wins setters) — so this explicit
block, included after the default from the class body, overrides the default's
navigation_label/navigation_icon while the default itself keeps applying to every other
model that has no concern of its own.
Either concern can be added independently — a model doesn't need both just because it needs one.
Installation
Add to your host app's or ATOM's Gemfile:
gem "thecore_generators", "~> 3.0"
Running tests locally
Tests use a Rails::Generators::TestCase-based harness against the test/dummy Rails
app included in this repo (needed to exercise generators the way a real host app would).
test/dummy also boots real model_driven_api/thecore_ui_rails_admin (and their own
transitive thecore_backend_commons/thecore_auth_commons dependencies) as temporary
git-based dependencies — see the Gemfile's comment — purely so
test/generators/thecore/model_generator_default_concern_behavior_test.rb can prove the
no-concern default actually works at runtime, not just that no file was written.
bundle install
bundle exec rake test
If your shell has DATABASE_URL set to a PostgreSQL URL (e.g. inside the Thecore
devcontainer), unset it first — it overrides test/dummy's own SQLite3 test config:
env -u DATABASE_URL bundle exec rake test
bundle exec rake alone runs the same suite (test is the default Rake task).
To run a single test file:
bundle exec ruby -Itest test/generators/thecore/model_generator_test.rb
Releasing
Version lives in lib/thecore_generators/version.rb. Pushing a commit that bumps it
triggers .github/workflows/gempush.yml, which tags the commit with that version and
publishes to RubyGems (skipped if the tag already exists) — the same pattern used by the
other gems in this ecosystem (model_driven_api, thecore_backend_commons, etc.).
License
MIT — see MIT-LICENSE.