Postgresql JSONB nested form ruby on rails

245 views Asked by At

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

2

There are 2 answers

0
max On BEST ANSWER

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.

0
Pralish Kayastha On

I came across a similar issue recently. So I created a simple gem for this exact problem.

https://github.com/Pralish/acts_as_has_many

class Product < ActiveRecord::Base
  acts_as_has_many :option_types
  acts_as_accepts_nested_attributes_for :option_types
end
f.fields_for :option_types, @product.option_types |ff|
  ff.text_field :name
  ff.select :values, multiple: true