Reference

# Nested & collections

Nested attributes, collection inputs, and the escape valves dynamic forms need.

## Nested attributes: fields_for

`fields_for` yields a builder per association (single) or per item (has_many), with the correctly-indexed `_attributes` scope Rails' `accepts_nested_attributes_for` expects:

```ruby
f.fields_for(:line_items) do |item|
  item.field :description        # name="invoice[line_items_attributes][0][description]"
  item.field :quantity
end
```

The nested builder speaks the full field API — `field`, `row`, escape hatches, even further nesting — and inherits the parent form's theme and variants.

## JSONB / hash columns

For a hash-backed column that isn't a Rails nested-attributes association, `nested_attributes: false` nests under the **raw** name — no `_attributes` suffix:

```ruby
f.fields_for(:settings, nested_attributes: false) do |s|
  s.field :locale                # name="user[settings][locale]"
end
```

## Collection inputs

```ruby
f.collection_check_boxes(:role_ids, Role.all, :id, :name) do |b|
  render b.check_box
  render b.label
end

f.collection_select(:country_id, Country.all, :id, :name, prompt: "Select…")
```

`collection_check_boxes` emits the hidden empty field so an empty selection still submits, and yields a builder per item with `check_box` and `label` prewired. For a `belongs_to`, remember [inference](https://phlex-forms.zoolutions.llc/docs/inference) renders the association select from a bare `field :country` — `collection_select` is for the explicit cases.

## Unscoped mode & external widgets

Dynamic rows — phlex-reactive per-row editors, `<template>`-cloned rows — need **bare** field names the model scope would break. `scope: false` turns scoping off (while `scope: nil` still derives from the model):

```ruby
Form(model: @item, scope: false, url: item_path(@item)) do |f|
  f.field :quantity              # name="quantity"
end
```

External widgets bind through the public helpers — the same three the [custom-widget recipe](https://phlex-forms.zoolutions.llc/docs/escape-hatches) uses:

```ruby
f.field_name(:starts_at)   # "event[starts_at]"
f.field_id(:starts_at)     # "event_starts_at"
f.field_value(:starts_at)  # the model's current value
```