https://github.com/performant-software/user-defined-fields
Allow users to decide what data to capture
https://github.com/performant-software/user-defined-fields
Last synced: 6 months ago
JSON representation
Allow users to decide what data to capture
- Host: GitHub
- URL: https://github.com/performant-software/user-defined-fields
- Owner: performant-software
- License: mit
- Created: 2022-09-14T20:18:54.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2025-07-21T10:56:10.000Z (12 months ago)
- Last Synced: 2025-07-21T12:33:48.396Z (12 months ago)
- Language: Ruby
- Size: 51.8 KB
- Stars: 0
- Watchers: 4
- Forks: 0
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# UserDefinedFields
This gem is designed to serve and storage and configuration for allowing CMS users to dynamically define fields for their models.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'user_defined_fields'
```
And then execute:
```bash
$ bundle install
```
Or install it yourself as:
```bash
$ gem install user_defined_fields
```
## Usage
### Migrations
To install the database table necessary to support user defined fields, use the following command:
```bash
bundle exec rails user_defined_fields:install:migrations
```
To install the `user_defined` column on a model, use the following command:
```bash
bundle exec rails generate user_defined_fields:add my_model
```
This will generate the following migration:
```ruby
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
end
```
### Routes
The user defined field routes can be added by mounting the engine in `routes.rb`:
```ruby
mount UserDefinedFields::Engine, at: '/user_defined_fields'
```
### Controllers
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.
```ruby
class MyModelController < ApplicationController
include UserDefinedFields::Queryable
end
```
### Models
Models 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.
```ruby
class MyModel < ApplicationRecord
include UserDefinedFields::Fieldable
resolve_defineable -> (my_model) { my_model.parent }
end
```
### Serializers
To 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.
```ruby
class ParentModelSerializer < BaseSerializer
include UserDefinedFields::DefineableSerializer
end
```
To include the `user_defined` hash as an attribute, include the `UserDefinedFields::FieldableSerializer` in the model serializer.
```ruby
class MyModelSerializer < BaseSerializer
include UserDefinedFields::FieldableSerializer
end
```
### Project Architecture
User defined fields can be configured one of two ways: At the application level, or at the model level.
##### Application 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.
##### Model Level
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.
## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).