mcpField
D
dynamic-nested-attributes

dynamic-nested-attributes

github.com/rolemodel開発737 回インストール1 日前に更新
リポジトリ

dynamic-nested-attributes について

Dynamic Nested Attributes は、関連レコードをフォーム内で追加・削除する Rails スキルです。ネストされた属性、Simple Form、Turbo Streams、Stimulus を組み合わせ、子レコードを編集する開発者を対象としています。

主な機能

  1. 01関連へのネスト属性設定
  2. 02既存の子フィールドの表示
  3. 03Turbo Streams によるフィールド追加
  4. 04Stimulus によるフィールド削除
  5. 05ルートとパラメーターのチェックリスト

活用シーン

  1. 011つのフォームで複数の関連レコードを編集
  2. 02ページを再読み込みせずに子項目を追加・削除
  3. 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 データコントローラーとの統合
  • 一括操作向けのフォームオブジェクトパターン
  • 関連用のポリシーでスコープされたコレクション

コメント