Rails Scaffolds
Status: Implemented for the admitted Scaffold surfaces below. Other surfaces are listed gaps.
The complete stored Scaffold graph now reaches one immutable ScaffoldLowering result built from the exact
submitted-source index and same-generation Domain, relationship, query, Account, Policy, route, and descriptor
evidence. The result owns routes, definitions, recursive projections, typed inputs, bindings, associated-create forms,
returns, authorization decisions, query plans, preload paths, and precise omissions. Scaffold
lowering lists the admitted representative surfaces, and the reviewed GapSet lists each omitted
surface or child. Generated controllers, views, and forms are ordinary Rails scaffold source:
resources routes, model-bound forms, Pagy pagination, .preload relations, and direct redirects. A surface the
target cannot realize is omitted without deleting its admitted siblings.
On this page
- Scaffold lowering
- Web files and routes
- Mutation shapes
- Record display
- Pagination
- Associated collections
- Projections
- Forms
- Associated creation
- Preload
- Navigation
- Mutation destinations
- Generated source
- Code and checks
Scaffold lowering
ScaffoldLowering joins the complete retained Scaffold graph to exact submitted-source and same-generation Domain,
relationship, query, Account, Policy, route, and descriptor evidence once. Its frozen result owns admitted
definitions and concrete route consumers; typed inputs, bindings, recursive render nodes, authorization decisions,
query and cursor plans, associated forms, returns, nested preload paths, and source-addressed
omissions. Public, item-authorized, environment-gated, and projection-gated consumers remain distinct. Protected
collection and member lookup starts from the admitted Policy relation. Action and collection-wide gates authorize
before presentation loading; views guard protected content. Web profile decisions target current_account.
The renderer does not scan raw graph rows, synthesize an authorization scope, or infer a return route.
The admitted representative definitions are:
| Plan | Entity | Definitions | Selected Rails routes |
|---|---|---|---|
| Oscar Party | Movie, Person | index, show, create, update, destroy |
all seven resource routes |
| Oscar Party | Credit | create, update, destroy |
create, edit, update, destroy |
| Oscar Party | Bookmark | index, show, create, update, destroy |
all seven resource routes |
| Oscar Party | Rating | create, update, destroy |
create, edit, update, destroy |
| Case Chat | User | profile, update |
singular /account and /account/edit |
| Case Chat | Case | index, show |
index, show |
| Case Chat | Conversation | index, show |
index, show |
| Case Chat | ConversationThread | show |
show |
| Case Chat | Message | create |
create |
| Case Chat | Notification | index, show |
index, show |
| Photogram | none | none | none |
Admission can preserve safe partial meaning. A selected unsupported Predicate or Ordering remains an exact consumer
gap; an index or admitted collection can survive without the filter or with deterministic id ordering only when its
projection says so. That fallback order is never reported as the authored Ordering. Current output accepts no
generic-text fallback for an unsupported Field kind and no unrestricted lookup before a protected decision.
Unsupported children are omitted without deleting admitted siblings, but an authored nonempty projection whose every
child fails never becomes an implicit descriptor view. Unsupported control types, relationship shapes, route pairs,
Policy ownership, bindings, associated forms, and return paths omit their exact consumer. Ordinary iOS and Android
clients continue to consume separate public-only navigation results and gain no protected index, profile, detail, or
mutation surface from this Web lowering. The Scaffold owner (repository-only) owns the detailed contract.
Lower each admitted authored definition through one exact-source, input-owned ScaffoldLowering result. Standard
resource routes use Rails resources; Case's Account-owned profile uses fixed Web-only /account and /account/edit
routes resolved from current_account. A retained definition needs a concrete consumer: index/show/destroy need their
matching route; create needs a create route or admitted associated-create consumer; update needs an edit/update route
or Account. new requires create, and edit requires update. A selected request-only create needs no New page,
associated form, or return destination. Public and otherwise supported protected creates use the same admission rule;
Policy shape controls access. Required-value coverage follows the actual consumer: each associated form may supply its
exact inverse Reference. If a selected standalone create lacks that required parent in its inputs, bindings, or
realized defaults, its ordinary endpoint remains generated with a partially_generated route gap. The owner's agent
completes its missing value supply; working associated forms remain available. A selected create without an admitted
associated form still needs the complete standalone source set. Membership authorization adds no separate direct-input
requirement to an associated form.
Those are the current renderer's rules for a surface it claims to realize, not a requirement that every future pre-alpha renderer prune Rails boilerplate to the authored route list. A later slice may emit a conventional full scaffold first and list unsupported routes, guards, query behavior, projections, forms, or returns in the reviewed GapSet. The extra surface is editable starter code, not authored meaning or proof that those consequences work. Such a slice must not report that fallback as the selected Ordering, Field behavior, or Policy.
The current Web renderer instead omits unsupported protected consumers and emits a narrow resources ... only: set;
that describes this release, not a general admission rule.
Web files and routes
WebScaffoldFiles consumes the immutable input-owned Scaffold lowering and same-generation collision claims.
It selects one ordinary task per generated routes, navigation, controller, locale, pagination, Scaffold view, form,
profile, or integration-test path. Each task renders only its final path and keeps the normal task owner, SQL guard,
and failure identity. The generalized renderer replaces legacy public-index output whenever the admitted graph needs
protected authorization, recursive projections, query choices, bindings, associated forms, dynamic returns, cursor
pagination, or profile behavior. A legacy public-only shape may still take the byte-for-byte predecessor renderer,
but the two projections never claim the same authored surface or output path.
Core's Domain-routes and shared-navigation seams remain application-global. They combine admitted resource routes,
the Account route with optional authored profile details, without transferring ownership to Account, Policy, or
an Entity controller. Resource entries use conventional Rails controllers and helpers. The profile uses singular
/account routes and current_account; it is not a resources :users member. Duplicate human navigation labels
remain valid because stable identities and collision-admitted paths are distinct.
Scoped inputs omit the URL-bound inverse Reference; separate required parent contexts share ordinary Rails actions and forms. Optional Plan overrides use direct routes.
Mutation shapes
The required-string-enum main-line parent admitted exact public indexes and the bounded public create/update shape are
admitted. The only admitted show extends that exact mutation shape with ordered index, show, new, create,
edit, and update routes; public index, show, create, and update definitions; and either an omitted projection or a
nonempty ordered projection of direct owner-local scalar Fields. Create and update may return to the same-Entity index
or the exact same-Entity show route selected from { "from": "mutation_record" }. Standalone public index plus
show, Association or recursive projections, and broader record-valued returns produce source-addressed warnings that
omit the surface. An optional Field Primary Descriptor is a blocking semantic error. A semantically valid but
target-unsupported descriptor omits dependent surfaces through its reviewed target gap. The destroy variant requires
the complete show-bearing shape, public authorization, no inputs, and an exact return to the same Entity's selected
public index. Broader destroy destinations and Policy authorization keep their surfaces out of the emitted set; every
omission joins the reviewed GapSet. Show and destroy do not add a native detail surface.
Record display
Resolve each Entity's primary_descriptor into an explicit reader chain wherever generated UI needs a whole-record
label. A direct descriptor reads its Field or system Field. An Association descriptor follows a singular
referencing-side traversal and continues through the target Entity's descriptor. Do not override to_s; emitting
ordinary source at each use site lets one generated view evolve without changing every other view. A multi-target
Reference behind that Association branches over its closed targets when their descriptors differ. Semantic validation
still resolves every locator and rejects optional sources and descriptor cycles. Descriptor use does not cancel
authored encryption or log-redaction behavior. The current Compiler admits only a direct required emitted scalar or
system Field, or one required ordinary single-target forward Association hop that terminates in one of those direct
descriptors. Public index and show preload that hop and render its explicit reader chain; multi-target branching and
longer chains remain future lowering.
Public Web admission consumes the same-generation semantic Primary Descriptor receipt. It accepts one required
ordinary single-target forward Association hop ending in a required emitted scalar or system Field, retains exact
source/provenance, and emits the explicit reader chain plus preload for index and show. Public Scaffold Reference
selects reuse that descriptor. The one-hop form eager-loads its Association, orders by terminal value and target id,
and maps labels and IDs from one result query. The private Policy-gated index authorizes first, then reuses the
descriptor reader, preload, and provenance. Multi-hop, multi-target, optional, unsupported-terminal, and broader
consumer shapes are omitted and listed at their service, semantic, or target boundary. A foreign target or profile is
caller misuse at this exact-profile boundary and fails before any projection is built. When whole-Application
qualification has already admitted an exact ordered Domain catalog, the web projection consumes that same catalog.
Pagination
Index relations apply the admitted authorization scope before Predicate, Ordering, preload, and pagination. An
unsupported selected Predicate is an exact child gap; an unsupported Ordering is an exact gap and uses
deterministic id fallback without claiming the authored order. Cursor pagination requires an input-owned
deterministic keyset. Root show/profile collection previews use Pagy Countless with explicit page: 1, limit: 5.
Pagy queries at most six rows and
display five, using the extra row only to decide whether to offer View more…. This final list row uses an
ordinary Rails link with a plain-text label rather than another heading. It opens the
dedicated collection page from its beginning, independent of its page size or pagination mode. The parent page's
page parameter cannot move a preview. Previews do not count the collection.
Every admitted collection derives a one-level parent-scoped read route and a separate paginated page, even without
a target global index. Show/edit/update/destroy routes stay flat; associated New and create use the collection URL.
The full request repeats the parent show/profile
authorization and the projection's gate or item scope before querying its records. Its rows preserve the same
Predicate, Ordering, supporting content, and separately authorized destination links.
This uses ordinary Rails Associations and named GET routes. The pinned Rails 8.1.3.1 route-name
check
rejects duplicate explicit names; the
mapper
accepts as: without changing the path. Pagy 43.6.1 supplies
offset pagination by default,
Countless for previews, and
keyset for an authored cursor
choice. No new pagination library, nested CRUD tree, or Plan setting is needed.
Cursor requests use Pagy's native decoder and Active Record
adapter. Malformed
Base64/JSON may recover to page one. Some crafted shapes, extreme values, or NUL-containing strings can still raise
server errors; the application promises neither exact-arity admission nor universal 400 responses. It adds no
duplicate decoder, per-column validator, size cap, or global exception rescue. Normal HTTP transport limits still
apply. Ordered timestamps use the documented serialization
hook to write iso8601(6) values;
Rails' default millisecond JSON representation can otherwise repeat or skip rows. Other cursor values keep native
serialization, including legitimate long text values.
Small shared/_pagination and shared/_cursor_pagination partials render pagy.series_nav and pagy.next_tag
directly with ERB's HTML-rendering syntax. Their relative translation scopes preserve labels and accessibility
text. The pinned Core styles their ordinary .pagination class. Pagy escapes its URL parameters and expects
application-supplied options to be
trusted or escaped, as its
safety guide explains. The emitted labels are
fixed translations. A second sanitizer allowlist and forwarding helper add no application behavior.
Select each pagination partial from emitted indexes and full collection pages, including Account profile
collections. Emit PAGE_LIMIT = 24 only in a controller with one of those actions; five-record previews keep
their inline limit. Cursor-only pages retain the shared empty-page reset copy they use even when no offset
partial is emitted. Preview collection copy includes View more; full collection pages do not use that label.
Associated collections
Direct has_many and the admitted indirect direct-has_many/forward-Reference shape start from
parent.association. Rails retains its parent constraint and admitted intermediate Predicate; the emitted
indirect Association already uses distinct for one destination per identity. The same Relation receives the
selected authorization scope, presentation Predicate, Ordering, and preloads. Pagy's pinned Active Record adapter
qualifies cursor comparisons with the destination table, so these through queries need no outer ID subquery to
avoid ambiguous columns. The displayed Association supplies the final URL segment. Index and nested
collection projections, other indirect shapes, and conflicting browse paths remain explicit projection gaps.
A repeated Association presentation or the reserved edit segment cannot share one browse path.
A helper-name collision preserves the collection and its URL. Existing resource, profile, Account, and pinned
Core helpers retain their names. A scoped browse or New helper adds _collection only when its ordinary name is
occupied, repeating the suffix until it avoids both allocated helpers and other scoped helpers' preferred names.
Thus Order.items may use order_items_collection_path beside OrderItem's order_items_path, while their
paths remain /orders/:order_id/items and /order_items. Sibling scoped helpers follow the same allocation rule.
Rails' ordinary as: option supplies the distinct name. A scoped form uses polymorphic routing when model
inference selects its actual helper; aliases, collision suffixes, and inflection differences otherwise supply an
explicit compiled URL. This changes no authored meaning and adds no gap; conflicting browse paths still follow
the omission rule above.
Preview and full-page rows contain projected values and an optional destination link, with no edit/destroy controls. Selected and authorized edit/destroy actions appear on the record's detail page when show is selected. Otherwise their flat routes and edit form remain generated without a scaffold link; the application owner adds an appropriate entry point. This ordinary incomplete scaffold state adds no gap or compilation refusal. Empty and small collections have a browse route but no View more… row. An admitted associated create has an Add link at every collection size on both surfaces; both links open the same scoped New page with its direct Association/create binding. Only actual gates produce a collection visibility decision; public and item-scoped cards render directly. A protected create checks its own Policy after the collection gate permits presentation. Public create needs no permission flag or view branch.
Projections
Field projections use typed readers. Association projections use the qualified relationship and target Primary
Descriptor; omission of the entire projection requests descriptor fallback only when the author truly omitted it. A
nonempty authored projection whose every child is unsupported does not become an invented descriptor view. Index and
show descriptors use their required typed reader, with Rails localization for date/datetime and true/false copy for
Boolean values. They have no missing-record fallback. Optional projected Fields retain missing-value copy; projection
and descriptor headings call human_attribute_name. An admitted target show route turns an authored Association
descriptor or child-bearing projection into one separately authorized link; denial preserves the already-authorized
text. The renderer does not synthesize an unauthored reverse Association. Partial siblings survive. Oscar's Movie
Credit collection demonstrates that boundary: the collection and nested Person association survive, while the
unsupported billing_order dependency becomes id fallback, Position stays a service gap, and required enum storage
admits the Role display and authored-label input. The associated Credit create form is admitted. Bookmark priority
likewise admits create/update controls and index/show display, while its selected rank Ordering remains a gap with
deterministic id fallback.
Forms
Create and update inputs map Boolean, date, datetime, decimal, integer, language-code, long-text, short-text,
time-zone, URL, enum, and direct Association controls with exact requiredness, length maximum, option descriptor,
parameter, attribute, and numeric-validation facts. Raw-input integer and decimal validation runs before Active
Record coercion. A time-zone control displays human-readable Rails zone labels while submitting canonical TZInfo
identifiers, preserving an existing admitted identifier through edit. An enum control displays authored value
names and submits stable keys in authored order. Each required emitted destination has an admitted create-time source:
control, binding, the realized required-datetime current_time default, an admitted required-enum literal-key
default, required State Machine initial-state source, or, only in associated-form context, the exact
inverse Reference.
Conditional-presence owners remain actual controls in both forms. Derivations are not sources in this release, and
derived controls are omitted. New and associated New select the create form body; Edit selects the update body.
Those same consumers select the form partial, strict locals, dropdown loaders, and form copy. Request-only writes
retain their admitted strong parameters and response behavior. Within one Entity, contexts with identical ordered
controls share a concrete partial after omitting the route-bound inverse. Different controls or order emit separate
partials, selected explicitly by New or Edit and reused on failed submissions. Each partial has only its required
option locals and static error-field mapping; fields have no action or parent-type visibility branches.
Matching accepted parameter names and request handling share one <resource>_params method, regardless of
control order or action authorization. Different allowlists and route-dependent inverse exclusions retain
action-specific helpers; a Create action without editable inputs retains no parameter helper.
Index actions build and bind a New-link candidate only for authorization against that record, including its
required preloads. Public and current-Account New links need no candidate; ordinary New-page setup remains.
Model-bound form_with infers the ordinary scope, URL,
and HTTP method. Scoped creates
pass the parent and child models; helper aliases, inflection differences, and singular /account retain explicit
URLs. Namespaces and novalidate preserve the existing accessible server-validation flow.
A date control receives the tightest inclusive ISO min and max from emitted unconditional date-literal
comparisons. Strict bounds move one calendar day inward. Bounds outside the control's four-digit year range,
conditional comparisons, and unsupported comparisons supply no HTML or calendar restriction. The form's provenance
includes the Validation subjects that supply its selected bounds.
The native date input and shared React calendar use those bounds as input guidance; the generated Rails validators
remain the persistence boundary.
Generated locale entries use Rails activerecord.models, activerecord.attributes, and helpers.submit keys.
Ordinary model-bound labels use Rails form.label inference; application helpers.label overrides work normally.
Projection headings and shared controls retain explicit human_attribute_name lookups. References emit the
authored label for both the logical Association and _id attribute; shared controls explicitly select the logical
Association label so controls and errors share that name. A Reference select requires a direct or admitted
one-hop Primary Descriptor and retains an empty choice. A direct descriptor uses scalar order and pluck;
tuples pass through unchanged unless boolean/date/datetime labels require localization. A one-hop descriptor
uses one eager-loaded query ordered by the terminal value and target
id, then maps labels and IDs without traversal queries. Only required References add the HTML required
attribute. Protected forms authorize their initialized record before querying options.
Server bindings run before persistence. current_account may target only the realized Account Reference in a
non-public Account-backed context; it cannot be assigned to a Field or silently turn a public create into an
authenticated request. The historical private Policy-gated index likewise authorizes before constructing its
paginated relation or preloading a one-hop descriptor target.
Associated creation
An associated-create form is limited to one direct unpredicated inverse has_many, one admitted target create
definition, no conflicting parent binding, and one unambiguous parent/target context. It derives its scoped New
and POST routes without requiring a selected standalone Create. Parent cards and full collection pages link to a
dedicated scoped New page. Their create-link authorization builds and binds a
child only when its Policy checks that child; an environment gate checks current_account directly. Normal
helpers such as movie_credits_path and
new_movie_credit_path name explicit routes; different parents share the child's new, create, and form.
Small branches use only request.path_parameters, load and authorize their concrete parent, then call
parent.credits.build(attributes). The form and strong parameters omit exactly the route-bound inverse input;
other selected inputs and server bindings remain. Each form request owns its remaining option queries, so separate
parent forms may share target Association inputs without sharing form state. The form infers its POST route from
the parent and child models when that matches the selected helper; aliases and inflection differences use an
explicit compiled URL. Source pointers and form identifiers are not a generated request protocol.
Cancel and default success return to the scoped collection; only an explicit associated return_to overrides
success. A profile collection does not acquire this resource-member context. Predicated collections, indirect
creation, longer return chains, duplicate parent/target contexts, and omitted target definitions remain gaps.
The plain New page uses ordinary Rails navigation and can later be enhanced at the same URL; no modal, inline form,
or new-destination attachment workflow is inferred. Creating a Credit selects an existing Person plus the role.
Preload
Public, item-authorized, and gate authorizations remain distinct. A protected collection or member lookup starts
from the exact Policy relation scope when required. Environment gates authorize current_account; projection
gates authorize the parent scaffold record. Relations use ordinary .preload(...) with the nested graph needed
for Policy decisions, controls, and presentation. For example, a Message reply needs both its author for display
and its thread's Conversation members for the read decision. Rails batches those association loads for the
selected records. Denied associated records may enter server memory; allowed_to? still guards their content,
and destination-link and control checks retain their separate decisions.
Action and collection-wide gates authorize before presentation loading. A gate that needs the scaffold record
loads its decision dependencies first. Direct record preloading remains useful after that gate, for an existing
current_account, and for a newly built record; these contexts do not have a relation awaiting materialization.
Preload paths stay relative to the record that owns them. The nested graph avoids repeated lazy loads and batches
traversal queries; authorization scopes, member checks, mutation checks, Ordering, and pagination remain in place.
Deeper non-public projection shapes remain omitted pending separate qualification. A representable preload graph
alone does not establish support or alter the reviewed GapSet.
The pinned Rails 8.1.3.1 preload API accepts nested Hashes and Arrays and batches separate association queries. Action Policy 0.7.6 supplies the record checks and controller API. These APIs preserve the separate choices of which records belong to a relation and which content or actions are authorized for each record.
Navigation
Web main navigation is target-specific. It admits public indexes, current-account-protected entries, explicit
current-account gates, and one authenticated /account destination with optional Policy-controlled profile details.
Ordinary iOS and Android clients consume separate public-only projections, retain their existing output, and do not
inherit Account or the protected Movie and Bookmark links. The Scaffold slice introduces no target-neutral navigation
contract.
Web navigation consumes this exact Scaffold result. Public indexes link directly; item-authorized entries require
a current account; explicit gates call the selected gate rule; and profile links only after the profile rule.
Fixed /account remains separate. Ordinary iOS and Android clients consume their public_only: true navigation
projections, do not inherit profile or protected Web entries, and receive precise partial rows when the Web-only
consequence needs disclosure.
No target-neutral Scaffold navigation projection is invented.
Mutation destinations
Derive the Screens defaults (repository-only) from the emitted interaction. Standalone
New/Edit redirects to the saved record; scoped associated create returns to its collection. Delete controls appear on
record details, and destroy defaults to that record's collection, then the existing home route. If a preferred
form-return detail is unavailable, use its admitted collection, then home. Profile editing returns to profile_path.
Optional Plan return_to overrides retain their admitted resource meaning. Emit direct route expressions, including
explicit overrides. Resolve a record-dependent destroy destination before deletion. Omitted override routes and
current-location overrides remain gaps; they do not silently become defaults.
Supported redirects consume no submitted destination URL and need no validated_return_to, hidden URL, or
mutation-record placeholder token. Ordinary New/Edit links have no navigation query parameter. Scoped forms
derive their parent only from the URL and preserve its lookup, authorization, inverse assignment, and
validation-error rendering without submitted context fields. Destroy retains its authored record lookup and
authorization; it consumes no parent context. The removed collection-row controls no longer need a separate
contextual-delete helper. Supplied URLs cannot override these server-owned destinations. Referer and session
history play no role. Rails' public url_from remains appropriate if future supported behavior
needs a submitted location; the current slice does not need one.
Failed form-backed creates and updates render the same form with values, errors, and parent context. Successful
form-backed mutations use 303 See Other. A selected standalone create without New or an explicit return uses
empty 201 Created/422 Unprocessable Content responses even when associated forms share its definition. The
scoped invocation retains its form, parent, and redirect. Authored standalone returns retain their redirects
without a form; a request-only update returns empty 422 on failure.
Destroy emits ordinary destroy! and its 303 redirect when no generated destroy behavior can normally refuse.
The existing ReferenceDeletion entries select the success/refusal branch for :restrict_with_error, directly
or through emitted dependent: :destroy Associations. Save validations, AASM initialization, and database-only
restrictions do not select that branch. No runtime callback inspection or broad exception rescue is emitted.
A refusal redirects to the same selected destination with the model's errors.full_messages.to_sentence in the
alert. Rails does not copy a restricted child's errors onto its parent: indirect refusal rolls back the deletion
but can leave the alert empty. A developer adding a destroy restriction later may also need to add controller
feedback. This follows the
direct-route structure of the Rails 8.1.3.1 scaffold; the
decision (repository-only) records the comparison and retained context.
Generated source
Local names
Generated resource vocabulary stays conventional. The Compiler preserves authored public model, controller, route,
instance-variable, parameter-scope, helper, and table projections; it does not globally rename every record to a
the_... form.
Public index record scopes and one-hop Reference-option maps allocate their compiler-private bindings. The mutation
index declares its unparenthesized link_to helper; its remaining helpers are parenthesized or use _path-suffixed
names that cannot equal the unsuffixed record binding. Scoped creation allocates its private parent record,
collection path, and optional form URL beside the child's instance variable. Entity Parent Record keeps
@parent_record; its scoped parent uses @the_parent_record. The same rule protects Collection Path and Form URL
without reserving those Entity keys. Other generated Scaffold scopes use fixed compiler-private locals.
Generalized Scaffold output uses @cases.each do |case_record| for reserved case, preserving public Case
vocabulary. The retained legacy public-index and private Policy-gate allocator lets an authored-derived local win
unless it is a target-profile Ruby keyword or collides in scope; later helpers move only when needed. There, Movie
uses movie, Case uses the_case, and a helper already named the_case becomes the_the_case. An Entity named
Descriptor may keep descriptor while a same-scope display helper becomes the_descriptor. The mutation index
reserves link_to, so Entity Link To uses the_link_to there while retaining public LinkTo, /link_tos, and
link_to_path. The current Analyzer still blocks generated constants colliding with Class, Module, or Thread
as an implementation exception; the target rule treats them as gaps and omits or partially generates affected
output unless no bootable residual exists. The Rails profile owns the exact keyword
set and allocation rule.
Redirects and Cancel links use route expressions rather than shared return_to or cancel_to instance variables.
The renderer emits ordinary inspectable Rails source from the immutable admitted projection. Resource routes use the
exact helper, path, controller, action, and parameter names that target qualification checked. Singular profile
routes are separate from resources; omitted or incoherent route and definition pairs do not enter task discovery
and remain listed gaps.
Projections and display
A projection recursively renders admitted Fields and Associations in authored order. A singular Association without children displays its qualified target Primary Descriptor. Root show and profile collections receive their own scoped query for direct Associations and the admitted indirect shape. A singular item immediately inside a collection may retain its own item Policy. Collection projections on indexes or below another Association projection, other indirect query shapes, repeated-table Policy joins, and deeper non-public presentation remain precise omissions.
Date and datetime values use Rails localization with the standard :long format, including the year in the default
English locale. Applications can override the locale's date and time formats. False remains “No” and zero remains 0;
invalid missing descriptor data receives no invented record-name fallback. Enum labels use ordinary Rails I18n
lookups, with escaped text even for value keys ending in _html. No
additional enum translation library or runtime model wrapper is generated. State Machine values use their authored
State names under AASM 6.0.0's translation
keys,
activerecord.attributes.<model>.<field>/<state>. The scalar Field label stays beside those keys, so the attribute
name and state names can both be translated without a nested-key collision.
Details and new/edit forms use the index card width. A details card has one h1, then right-aligned ghost actions
with matching icons: an explicitly named index destination such as “All movies”, Edit, and Delete. Native requests
omit the web index-return control. The scalar primary descriptor is not repeated below its title. Other properties
use one-column dt/dd markup without attribute dividers; top-level associated collections occupy sibling cards.
Form action buttons use the stock large preset. A standard Tailwind container query stacks full-width form actions
in narrow cards and uses natural-width actions at the named @md breakpoint; fields and actions have no divider.
An authored Association projection contributes a details destination only when its target show route and exact authorization survive admission. Its descriptor is an ordinary link; selected child properties may carry a View control. A row whose projection omits its own descriptor keeps a separately authorized View control for its own show route. This keeps multiple authored Association destinations usable without nested links or choosing one destination for the entire row. The renderer never invents an unauthored reverse Association or removes explicit join properties.
Rails collection rendering composes entity-owned row partials. An index uses, for example, credits/_list_item;
a matching associated projection reuses it. Different projections use contextual partials such as movies/_credit
and people/_credit, shared by that parent's preview and full collection page. A show page composes its main record
partial, such as movies/_movie, and sibling collection cards. Only selected presentations are emitted. Strict locals
name the record and its presentation options; DOM IDs distinguish a main record from its rows in each collection.
This provides reusable Rails and Turbo targets without adding automatic live updates.
Inputs and copy
Create and update accept only admitted controls and strong parameters. An enum select and every admitted read-only
enum projection look up the same enums.<model>.<field>.<key> entry in config/locales/scaffolds.en.yml. The
generated English catalog preserves each authored value name exactly; select options retain authored key order and the
empty choice. Editing that locale or adding another Rails locale changes both displays without recompiling the Plan.
Submitted and stored values remain stable keys. Enum admission and State Machine presentation are unchanged.
Screen, action, form-submit, and pagination copy follows the emitted pages and controls. Model, attribute, Reference, enum, State, and error labels remain available, as do translations used by retained Core components. Account edit/form/update copy follows the selected editable self surface. A custom profile's Association View and collection labels follow those rendered projections.
Server bindings run after submitted inputs; current_account is valid only for an admitted Account Reference.
Associated create builds through the authorized parent's collection, applies bindings, authorizes that initialized
record, and then saves it. The scoped form omits a selected inverse-parent input and excludes its submitted value;
standalone and other-parent forms retain their remaining inputs. If no invocation context accepts editable inputs,
create calls ordinary build/new without a parameter helper. Mixed contexts retain strong parameters where needed
and use {} for a no-input branch, so a normal submission need not include a model parameter. A server binding
cannot repeat the parent assignment.
Static collection/profile returns carry no record. A mutation-record show may use no step or one required Reference step; the latter uses its foreign key without loading an unneeded record. Destroy cannot return to the deleted record's own show.
Authorization in generated source
Every protected mutation authorizes before writing. Generated controls repeat the action's consumer rule.
Account always resolves current_account. The Account link and credential forms require authentication.
Remaining target gaps include unsupported Field/control kinds, longer or optional return traversals, broader relationship query plans, richer formatting, state-machine controls, repeated-table Policy joins, and deeper protected nested descendants. The reviewed GapSet fixtures hold the exact representative matrix.
Code and checks
A separate narrow browser-only Movie Catalog qualification uses a one-hop Association Primary Descriptor for Reference
inputs. Its option query eager-loads that hop, orders by the terminal descriptor and target id, and maps label and
ID pairs from one result query. The target Entity's public form selects the descriptor Association explicitly. The
script materializes that application, verifies its exact manifest, migrates and schema-loads fresh databases,
and repeats the same request and persistence checks after both setup paths. It proves create with the required
Director and either no Consulting Director or a selected Consulting Director; nil-to-target, target-to-another-target,
and target-to-nil Consulting Director updates; logical conditional-presence errors and corrective resubmission;
required and optional HTML requiredness; one-query Association-descriptor option ordering, strict eager loading,
zero-query cached label reads, deterministic descriptor options, and no option query during successful writes. The
generated forms do not expose unselected attributes. Model-invalid writes render logical errors with 422; valid
writes persist only admitted inputs and redirect with 303 to the selected same-Entity index or mutation-record show.
A submitted non-nil optional Reference ID whose target no longer exists can still reach the database foreign key and
raise; friendly stale-option handling remains later work. Index titles reach the detail page. That page renders the
independent Movie descriptor followed by notes and title in authored order, preserves multiline text, escapes authored
HTML, omits unselected data, and includes back and edit links. Ordinary missing records return HTTP 404; index/edit
links and forms carry no return URL. The former unsafe destination 400 checks were retired because the controller no
longer consumes a submitted location. The separate redirect-default
smoke (repository-only) checks that an extra submitted URL cannot change the
server-owned destination. The generated iPhone project remains outside this browser-only show proof.