cocoonからstimulusに置き換えました

2025/02/22 | Ruby on Rails

railsのcocoonは親フォームで子要素を作成できる便利なgemでしたのでよく使っていましたが、jquery依存でしたのでstimulusに置き換えてみました。stimulusの設定は終わっている前提です。hamlとsimple_formを使用しています。

rails 7.0.8.7
ruby 3.2.6

model/post

class Post < ApplicationRecord
  accepts_nested_attributes_for :post_tags, reject_if: :all_blank, allow_destroy: true
end

app/javascript/nested_controller.js

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["container", "template"];

  add(event) {
    event.preventDefault();
    const template = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime());
    this.containerTarget.insertAdjacentHTML("beforeend", template);
  }

  remove(event) {
    event.preventDefault();
    const wrapper = event.target.closest(".nested-fields");

    if (wrapper) {
      const destroyField = wrapper.querySelector(".destroy-field");

      if (destroyField) {
        destroyField.value = "1";
        wrapper.style.display = "none";
      } else {
        wrapper.remove();
      }
    }
  }
}

app/views/posts/_form.html.haml

#post_tags{ data: { controller: "nested-form" } }
  .nested-fields-container{ data: { nested_form_target: "container" } }
    = f.simple_fields_for :post_tags do |post_tag|
      = render 'post_tag_fields', f: post_tag
  .links
    = link_to 追加, "#", data: { action: "nested-form#add" }, class: "btn btn-primary"
  
  / フィールドのテンプレート
  = content_tag :template, id: "post_tag_template", data: { nested_form_target: "template" } do
    = f.simple_fields_for :post_tags, PostTags.new, child_index: "NEW_RECORD" do |post_tag|
      = render 'post_tag_fields', f: post_tag

app/views/posts/_post_tag_fields.html.haml

.nested-fields
  = f.hidden_field :_destroy, class: "destroy-field", value: "0"
  .row
    .col-lg-10
      = f.input :post_tag_text
    .col-lg-2
      = link_to 削除, "#", data: { action: "nested-form#remove" }, class: "btn btn-danger"