north_celt
north_celt

Reputation: 25

How to create a form in Rails with a variable number of jsonb items?

I have a model that stores modifiers for each year, for a variable number of years. It might be 0, it might be 10, it could be 50. The modifiers are not the same, and require different details depending on the type that they are.

The modifiers are only ever retrieved with the model, and don’t need to be sorted or queried or anything separately. Ideally, I’d like to just store them as JSON in one field on my model.

My question is how would I go about presenting a form that allows you to attach one or more modifiers to it? Basically I need the ability to add a different set of fields, depending on the type of modifier. And I need to do it repeatedly (like an add more button. It could either add one by type, or add one more generically with a select for the type)

I think this should be possible with Stimulus but I’m pretty lost how to do it on both the rails model/form side and the stimulus side.

Upvotes: 0

Views: 49

Answers (1)

mustajab zaheer
mustajab zaheer

Reputation: 1

Add methods like these in you stimulus controller

  addModifier(event) {
    event.preventDefault()

    // You can customize the new modifier HTML template as needed
    const newModifierHTML = `
      <div class="modifier-fields">
        <div>
          <label for="modifier_type">Modifier Type</label>
          <select name="your_model[modifiers][][modifier_type]">
            <option value="type_1">Type 1</option>
            <option value="type_2">Type 2</option>
          </select>
        </div>
        <div>
          <label for="value">Value</label>
          <input type="text" name="your_model[modifiers][][value]">
        </div>
        <button type="button" data-action="modifiers-form#removeModifier">Remove</button>
      </div>
    `
    this.containerTarget.insertAdjacentHTML("beforeend", newModifierHTML)
  }

  removeModifier(event) {
    event.preventDefault()
    event.target.closest(".modifier-fields").remove()
  }

Create a form that allows adding multiple modifiers. Use nested fields to manage different types of modifiers and you are good to go and make sure to add column inside your modal which with jsonb type.

<%= form_with(model: @your_model, local: true, data: { controller: "modifiers-form" }) do |form| %>
  <div id="modifiers-container" data-modifiers-form-target="container">
    <% @your_model.modifiers.each do |modifier| %>
      <%= render 'modifier_fields', form: form, modifier: modifier %>
    <% end %>
  </div>
  <button type="button" data-action="modifiers-form#addModifier">Add Modifier</button>
  <%= form.submit %>
<% end %>

Create a prtial like this if you like :D

<!-- app/views/your_model/_modifier_fields.html.erb -->
<div class="modifier-fields">
  <div>
    <%= form.label :modifier_type %>
    <%= form.select :modifier_type, options_for_select([['Type 1', 'type_1'], ['Type 2', 'type_2']], modifier[:modifier_type]), {}, { name: 'your_model[modifiers][][modifier_type]' } %>
  </div>
  <!-- Add other fields based on the type of modifier -->
  <div>
    <%= form.label :value %>
    <%= form.text_field :value, value: modifier[:value], name: 'your_model[modifiers][][value]' %>
  </div>
  <button type="button" data-action="modifiers-form#removeModifier">Remove</button>
</div>

Upvotes: -1

Related Questions