This gem is designed to serve and storage and configuration for allowing CMS users to dynamically define fields for their models.
Add this line to your application's Gemfile:
gem 'user_defined_fields'And then execute:
$ bundle installOr install it yourself as:
$ gem install user_defined_fieldsTo install the database table necessary to support user defined fields, use the following command:
bundle exec rails user_defined_fields:install:migrationsTo install the user_defined column on a model, use the following command:
bundle exec rails generate user_defined_fields:add my_modelThis will generate the following migration:
class AddUserDefinedFieldsToMyModel < ActiveRecord::Migration[7.0]
def up
add_column :my_model, :user_defined, :jsonb, default: {}
add_index :my_model, :user_defined, using: :gin
end
def down
remove_index :my_model, :user_defined
remove_column :my_model, :user_defined
end
endThe user defined field routes can be added by mounting the engine in routes.rb:
mount UserDefinedFields::Engine, at: '/user_defined_fields'Each individual field can be configured to be searchable or non-searchable. A searchable field will be included in the query when a user provides the "search" parameter on the API request.
Behind the scenes, this uses the PostgreSQL jsonb query syntax to build the SQL used to find the record. For performance reasons, it's important that the GIN index be created on the user_defined field (explained above) and that the user_defined field doesn't contain nested objects.
class MyModelController < ApplicationController
include UserDefinedFields::Queryable
endModels that include the UserDefinedFields::Fieldable concern will be treated as the models that store the user defined data. The will be available in the dropdown list when configuring user defined fields.
Applications that define user defined fields at the model level should call resolve_defineable class method with a lambda function that returns the defineable model.
class MyModel < ApplicationRecord
include UserDefinedFields::Fieldable
resolve_defineable -> (my_model) { my_model.parent }
endTo include the user_defined_fields array as a set of nested attributes, include the UserDefinedFields::DefineableSerializer in the serializer for whatever model the user defined fields belong to. This is only necessary for fields defined at the model level.
class ParentModelSerializer < BaseSerializer
include UserDefinedFields::DefineableSerializer
endTo include the user_defined hash as an attribute, include the UserDefinedFields::FieldableSerializer in the model serializer.
class MyModelSerializer < BaseSerializer
include UserDefinedFields::FieldableSerializer
endUser defined fields can be configured one of two ways: At the application level, or at the model level.
If configured at the application level, each record in the specified table will contain the same user defined fields.
For example: You could define first_name and last_name fields for all of the people records. Anytime a user is editing a a person form, the first_name and last_name fields will be available as inputs.
If configured at the model level, records can contain different fields dependent on a parent record.
For example: You could define a location field for resources that belong to Project A, then define a project_stage field for resources that belong to Project B. On the edit for for Project A, only the location field will be available. On the edit form for Project B, only the project_stage field will be available.
The gem is available as open source under the terms of the MIT License.