Add custom fields to object in ROR application

Hard question, but this is how I would try to deal with it: I would make all the objects to be derived from a CustomField object, then I would create a one to many relationship between it and a Field model. Something like this:

create_table :field_types do |t|
  t.string :name  # This would identify the fields: checkbox, plain text, etc
end

create_table :fields do |t|
  t.belongs_to :custom_field, null: false, index: true
  t.belongs_to :field_type, null: false, index: true
  t.string :name
end

class Field < ApplicationRecord
  belongs_to :custom_field
  belongs_to :field_type
end

class CustomField < ApplicationRecord
  has_many :fields
end

This way you could just look into the specified fields on the database and mount it at the view.

Then I would create a table for each type of field that could be used by the users to save the data from the CustomField objects. For instance, I would check the Client field specifier, mount a view with checkboxes A and B. Then, I would get the data from the checkboxes and save each of them at the table Checkboxes with an identifier, so that I could tell that it came from clients.

Depending on what you need to do, another idea that pops to my head is to save the data as a JSON string into the database. This way you could have different fields with different values, all you would need to do is serialize and deserialize to save and load it from the database, respectively.

Sorry if it was a little confusing. Hope it helps.


Assuming your database is relational:

I would suggest to use Entity-Attribute-Value pattern: https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model.

Here is a gem for it: https://github.com/iostat/eav_hashes

Also document-oriented database like MongoDB would be an option, if you ever consider changing database. It is schemaless, so you can have different attributes for different instance.


I'm not aware of any out of the box options available, but you might be better off rolling your own on something like this anyway. It will allow you more flexibility, and shouldn't be terrible to implement. In terms of models, I'd probably go with a single-table inheritance table for the fields, probably using a jsonb column for customization options (assuming postgres):

create_table :fields do |t|
  t.string :type, null: false # TextField, ListField, etc.
  t.jsonb :config, default: {}, null: false
  t.belongs_to :contact
end

You can then subclass as necessary for different use-cases:

class Field < ApplicationRecord
  belongs_to :contact
end

class TextField < Field
  def required=(required)
    config[:required] = required
  end
end

class CheckboxField < Field
  def default_checked=(default_checked)
    config[:default_checked] = default_checked
  end
end

You can look into something like jsonb_accessor to make for a cleaner interface to the jsonb column.

Likewise, single-table inheritance looks like it may also make sense for the contacts as well, not sure what the base table should be, but maybe something like:

create_table :contacts do |t|
  t.string :type, null: false # Contact, Lead, Client
end

class Contact < ApplicationRecord
end

class Lead < Contact
end