Back to the Rails application overview
Read the Rails application model
Inspect the Rails model: field properties, parent associations, entity order, and prepared seed rows.
Rendered from
test/system/rb-solar/doc/model.md
in the engine repository. The model, the generators, the committed
application and the check.sh that renders and validates all
of it are in
test/system/rb-solar/.
The Rails example keeps entity names, fields, routes, actions, and seed
rows in model.aon. Each generator imports that file and selects the
values its output needs. Start with the application overview
for the entities and the running Rails architecture.
Run the example’s CLI
Clone the engine repository and enter the example directory:
git clone git@github.com:aontu-lang/aontu.git
cd aontu/ts
npm ci
cd ../test/system/rb-solar
Use the CLI from this checkout throughout these guides. Define a shell function in the terminal where you run the commands, and make the scratch directory the recipes write their intermediate documents to:
aontu() { node ../../../ts/bin/aontu.js "$@"; }
mkdir -p work
All commands below run from test/system/rb-solar. work/ is scratch
and is not committed; check.sh clears and recreates it. Ruby is needed
to run the Rails app; inspecting the model and generating files requires
Node.js and the engine dependencies, the generator runtime among
them. Follow the repository’s
installation instructions for its supported toolchain.
Read a field as data
The planet’s diameter field is declared in the model source:
field: diameter: {
name: "diameter"
json: "diameter"
fk: false
kind: "float"
required: true
pk: false
write: true
}
kind is the string "float". The migration generator interprets that
string as a Rails column type. required controls a presence validation,
write controls ordinary API input, and pk and fk identify keys.
These are properties defined by this example; aontu does not assign Rails
behaviour to them automatically.
The name property is the database column name. json is the response
property name. They can differ: terraform_state is returned as
terraformState. Keeping both names explicit lets the API preserve its
existing contract.
Inspect the entity without evaluating the generated application:
aontu view doc --depth 2 --at '$.entity.planet' model.aon
The command draws the planet’s key tree. $.entity.planet starts at the
document root; the depth limit keeps nested field and action definitions
out of this view.
Describe the parent relationship
Moon declares the names used for its parent:
moon: parent: "planet"
moon: parent_class: "Planet"
moon: parent_param: "planet_id"
moon: parent_controller: "planets"
moon: parent_title: "Planet"
The Active Record generator reads the parent class and
foreign-key parameter to write belongs_to. The
ERD generator reads the parent class and association
name to draw the relationship. The controller generators use the parent
information to scope moon queries to a planet.
Planet also declares its child association in children. The generator
uses that entry to write has_many with dependent: :destroy.
These declarations must agree; parent is an application convention,
not a built-in aontu relation that infers the other side for you.
Use maps for names and lists for order
Entities and fields are maps, so a field has a stable address such as
$.entity.planet.field.diameter. Walking a map visits sorted keys.
A migration must create planets before moons, so the model also declares:
sequence: [$.entity.planet $.entity.moon]
Each list entry refers to the entity already defined. It does not copy its fields into a second definition. The migration and seed generators read this list to preserve parent-before-child order.
An action’s rule is also a list. The API generator emits conditional
assignments in that order, so the last matching assignment wins.
The model puts lower-priority rules first.
Prepare values for a template
The seed data is imported from the reference application’s JSON file. The model adds a class name to each planet row:
rows: each($.seed.planet, _ & { class:"Planet" })
each applies a template to each selected value. _ is the current
row, and & combines that row with the added class property through
unification. The seed generator can
then read the row and its Rails class in the same place.
This matters for nested generation rules: put the values a rule needs on the node it matches. Do not assume an inner rule can read the outer rule’s current entity.
Continue with generating Rails code to see how these values become filenames, associations, routes, and view content.