---
title: "Read the Rails application model"
description: "Inspect the Rails model: field properties, parent associations, entity order, and prepared seed rows."
source: "https://aontu.dev/examples/rb-solar/model/"
---

[Back to the Rails application overview](https://aontu.dev/examples/rb-solar)

# 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`](https://github.com/aontu-lang/aontu/blob/main/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/`](https://github.com/aontu-lang/aontu/tree/main/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](https://aontu.dev/examples/rb-solar) for the entities and the running Rails architecture.

## Run the example’s CLI

Clone the engine repository and enter the example directory:

```sh
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:

```sh
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](https://github.com/aontu-lang/aontu/blob/main/ts/README.md) for its supported toolchain.

## Read a field as data

The planet’s diameter field is declared in the [model source](https://github.com/aontu-lang/aontu/blob/main/test/system/rb-solar/model.aon):

```aontu
    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:

```sh
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:

```aontu
  moon: parent: "planet"
  moon: parent_class: "Planet"
  moon: parent_param: "planet_id"
  moon: parent_controller: "planets"
  moon: parent_title: "Planet"
```

The [Active Record generator](https://github.com/aontu-lang/aontu/blob/main/test/system/rb-solar/gen/model.rb) reads the parent class and foreign-key parameter to write `belongs_to`. The [ERD generator](https://github.com/aontu-lang/aontu/blob/main/test/system/rb-solar/gen/doc/erd.mmd) 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:

```aontu
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:

```aontu
    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](https://aontu.dev/docs/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](https://aontu.dev/examples/rb-solar/rails-code) to see how these values become filenames, associations, routes, and view content.
