dynamic-nested-attributes について
Dynamic Nested Attributes は、関連レコードをフォーム内で追加・削除する Rails スキルです。ネストされた属性、Simple Form、Turbo Streams、Stimulus を組み合わせ、子レコードを編集する開発者を対象としています。
主な機能
- 01関連へのネスト属性設定
- 02既存の子フィールドの表示
- 03Turbo Streams によるフィールド追加
- 04Stimulus によるフィールド削除
- 05ルートとパラメーターのチェックリスト
活用シーン
- 011つのフォームで複数の関連レコードを編集
- 02ページを再読み込みせずに子項目を追加・削除
- 03一括作成または編集フォームの構築
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rolemodel/ rolemodel-skills --skill dynamic-nested-attributesインストール後、Claude Code で/dynamic-nested-attributesを入力して読み込まれたか確認します。
詳細
動的なネスト属性
概要
Turbo Streams と Simple Form を使用して、Rails のネスト属性に動的な追加・削除機能を実装します。このパターンでは、親フォーム内で関連レコードをインラインで追加・削除できます。
使用する場面
- ユーザーが複数の子レコード(has_many 関連)を管理する必要があるフォームを作成する場合
- ページを更新せずにネストされた項目を追加・削除する場合
- 関連レコードを一括で作成または編集する場合
- 追加のフィールドを段階的に表示するフォームを作成する場合
主なコンポーネント
1. フォームオブジェクトまたはモデル
- 関連に対するネスト属性を受け付けます
- モデルまたはフォームオブジェクトで
accepts_nested_attributes_for :association_nameを使用します
2. メインフォームのビュー
次の内容を含むフォームを作成します。
- 既存のネストされた項目を描画する
simple_fields_for - 新しい項目を追加するコンテナー要素(例:
#accessories) - Turbo Stream リクエストをトリガーする、新しい項目を追加するリンク
例:
= simple_form_for resource do |f|
= f.simple_fields_for :items do |ff|
= render 'item_fields', f: ff, resource:
= render 'add_button', index: resource.items.size
追加ボタンのパーシャル(_add_button.html.slim):
-# locals: (index:)
= link_to icon('add'), new_parent_item_path(index: index),
id: 'add_button', class: 'btn', data: { turbo_stream: true }
3. ネストされたフィールドのパーシャル
次の内容を含むパーシャル(例:_item_fields.html.slim)を作成します。
- インデックスに基づく一意の ID を持つコンテナーでフィールドを囲みます
- 削除機能用のデータコントローラーを含めます
- すべてのレコードに削除ボタンを表示します
- ネストされた項目のフォーム入力をすべて含めます
例:
fieldset id="item_#{f.index}" controller='destroy-nested-attributes'
= f.hidden_field :_destroy, data: { destroy_nested_attributes_target: 'input' }
= f.input :name
= f.input :quantity
.form-row__actions
= button_tag icon('delete'), type: 'button', class: 'btn btn-delete',
data: { action: 'destroy-nested-attributes#perform' }
4. コントローラーのアクション
次の内容を含む new アクションを実装します。
- 新しいネストされた項目を作成します
- 位置を追跡するための
indexパラメーターを受け付けます
例:
def new
@item = Item.new
end
5. Turbo Stream のレスポンス
次の内容を含む new.turbo_stream.slim ビューを作成します。
- インデックスを増やして「追加」ボタンを更新します
- 新しいネストされたフィールドをコンテナーに追加します
- 一意のフィールド名を確保するために
indexパラメーターを使用します - シンボルと空の URL を使用して、まだ保存されていない親オブジェクトにも対応します
例:
= turbo_stream.replace 'add_button', partial: 'add_button', locals: { index: params[:index].to_i + 1 }
= simple_form_for :parent, url: '' do |f|
= f.simple_fields_for :items_attributes, @item, index: params[:index] do |ff|
= turbo_stream.append 'items', partial: 'item_fields', locals: { f: ff }
6. 削除用 Stimulus コントローラー
クライアント側での削除を処理する Stimulus コントローラーを作成します。
JavaScript の例:
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ['input']
static classes = ['destroyed']
connect() {
if (!this.hasDestroyedClass) {
this.element.setAttribute(`data-${this.identifier}-destroyed-class`, 'is-hidden')
}
}
perform() {
this.inputTarget.value = '1'
this.element.classList.add(this.destroyedClass)
}
}
実装チェックリスト
- モデル/フォームオブジェクトに
accepts_nested_attributes_forを追加する -
simple_fields_forとコンテナー要素を含むメインフォームを作成する - 削除機能を備えたネストされたフィールドのパーシャルを作成する
-
indexに対応するコントローラーのnewアクションを実装する - turbo_stream のレスポンスビューを作成する
- クライアント側の削除用に Stimulus コントローラーを追加する
- ネストされたリソースの作成に対応するルートを更新する
- ネスト属性を許可するようにストロングパラメーターを更新する
- Pundit を使用している場合はポリシー認可を追加する
よく使われるパターン
親の選択に基づく動的なコレクション
フィルター済みのコレクションをネストされたパーシャルに渡します。
= render 'item_fields', f: ff, resource:, collection: resource.items
ルートの例
既存の new ルートを使用していない場合は、次のパターンを使用します。
resources :items, only: [:new]
すでに使用中のルートがある場合は、新しい名前空間付きコントローラーを作成します。
namespace :parent do
resources :items, only: [:new]
end
ストロングパラメーターの例
def item_params
params.require(:parent).permit(
:category,
:subcategory,
items_attributes: %i[
name
quantity
part_id
optional
hidden
]
)
end
関連するパターン
- Turbo Frame によるインライン編集
- Stimulus データコントローラーとの統合
- 一括操作向けのフォームオブジェクトパターン
- 関連用のポリシーでスコープされたコレクション
コメント
Markdown 対応