Supporting reference · Working design and evidence, not a promise of complete support.

On this page

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

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.

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.

References marked “repository-only” name implementation or internal material outside this public guide. They are intentionally not links. Publishing a design does not prove its implementation.