Search code examples
ruby-on-railsrubynested-forms

Multilevel / Triple Nested Forms regarding association has_many


I have the 3 classes Product, ProductVariant, Component and I want to apply a triple nested form in order to make it possible to set the values for Product, ProductVariant and Component when calling the view of Product.

Models

class Product < ApplicationRecord
  has_many :product_variants
  accepts_nested_attributes_for :product_variants
end

class ProductVariant < ApplicationRecord
  has_many :components
  accepts_nested_attributes_for :components
end

class Component < ApplicationRecord
end

Product's controller

 # GET /products/new
  def new
    @product = Product.new
    @product.product_variants.build.components.build
  end

  # POST /products or /products.json
  def create
    @product = Product.new(product_params)

    respond_to do |format|
      if @product.save
      ...
      end
      ...
    end
  end
...
    def product_params
      params.require(:product).permit(:name, product_variants_attributes: [:category, components: [:form]])
    end
end

Product's view

<%= form_with(model: product) do |form| %>
  ...
  <div>
    <%= form.label :name, style: "display: block" %>
    <%= form.text_field :name %>
  </div>
  <%= form.fields_for :product_variant do |va| %>
    <%= va.label :category, style: "display: block" %>
    <%= va.text_field :category %>
    <%= va.fields_for :components do |co| %>
      <%= co.label :form, style: "display: block" %>
      <%= co.text_field :form %>
    <% end %>
  <% end %>
  <div>
    <%= form.submit %>
  </div>
<% end %>

It's possible to initialize and save the object ProductVariant but for Component I get Unpermitted parameter: :components_attributes and I can't figure out why.


Solution

  • You should pass the components params the same way as the product variants, adding the _attrbiutes suffix.

    Change the following:

    params.require(:product).permit(:name, product_variants_attributes: [:category, components: [:form]])
    

    to:

    params.require(:product).permit(:name, product_variants_attributes: [:category, components_attributes: [:form]])
    

    https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html - One-to-many