ruby-on-railsactivemodelnested-form-for

Postgresql JSONB nested form ruby on rails


I have product as active record table and option_type as activemodel model. option types is an array of objects as follows,

[
  {name: 'color', values: ['red', 'blue']},
  {name: 'size', values: ['small', 'medium']}
]


class OptionType
  include ActiveModel::Model

  attr_accessor :name, :values, :default_value

  def initialize(**attrs)
    attrs.each do |attr, value|
      send("#{attr}=", value)
    end
  end

  def attributes
    [:name, :values, :default_value].inject({}) do |hash, attr|
      hash[attr] = send(attr)
      hash
    end
  end

  class ArraySerializer
    class << self
      def load(arr)
        arr.map do |item|
          OptionType.new(item)
        end
      end

      def dump(arr)
        arr.map(&:attributes)
      end
    end
  end
end

I want to desing a form_for with nested form for option_types so that user can add various option names and it's values. How to do it?

reference links are as follow,

Validation of objects inside array of jsonb objects with RubyOnRails


Solution

  • I know this isn't the answer you're hoping for but instead of just tossing the whole lot into a JSONB column and hoping for the best you should model it as far as possible in a relational way:

    class Product < ApplicationRecord
      has_many :options
      has_many :product_options, through: :options
    end
    
    # rails g model option name:string product:belongs_to
    class Option < ApplicationRecord
      belongs_to :product
      has_many :product_options
    end
    
    # rails g model product_option option:belongs_to name:string ean:string
    class ProductOption < ApplicationRecord
       belongs_to :option 
       has_one :product, through: :options
    end
    

    If your data is actually structured enough that you can write code that references its attributes then a JSON column isn't the right answer. JSON/arrays aren't the right answer for setting up assocations either.

    This lets you use foreign keys to maintain referential integrity and has a somewhat sane schema and queries instead of just dealing with a totally unstructed mess. If you then have to deal with an attribute that can have varying types like for example an option that can be string, boolean or numerical you can use a JSON column to store the values to somewhat mitigate the disadvantages of the old EAV pattern.

    Creating variants of a product could then either be done via a seperate form, nested attributes or AJAX depending on your requirements.