Have you ever wanted to add custom fields to your ActiveRecord models, like in Redmine or Jira, without altering the database schema or writing extra code?
I had the same idea!
That's why I created the active_fields gem.
It’s built on the EAV (entity-attribute-value) pattern. In the context of the gem, the entity is called a Customizable, the attribute is an Active Field, and the value is an Active Value.
Installation
-
Install the gem and add it to your application's Gemfile by running:
bundle add active_fields
-
Run install generator, then run migrations:
bin/rails generate active_fields:install bin/rails db:migrate
-
Add the
has_active_fields
method to any models where you want to enable custom fields:
class Post < ApplicationRecord has_active_fields end
-
Run scaffold generator.
This plugin provides a convenient API, allowing you to write code that meets your specific needs
without being forced to use predefined implementations that is hard to extend.However, for a quick start, you can generate a scaffold by running the following command:
bin/rails generate active_fields:scaffold
This command generates a controller, routes and views for managing Active Fields,
along with form inputs for Active Values and some useful helper methods.Note: Don't forget to add available Customizable types in generated Active Fields forms.
Note: The array field helper uses Stimulus for interactivity.
If your app doesn't already include Stimulus, you can easily add it.
Alternatively, if you prefer not to use Stimulus, you should implement your own JavaScript code. -
Add Active Fields inputs in Customizables forms and permit their params in controllers.
There are two methods available on Customizable models for retrieving Active Values:
-
active_values
returns collection of only existing Active Values. -
initialize_active_values
builds any missing Active Values and returns the full collection.
Choose the method that suits your requirements.
In most cases, however,initialize_active_values
is the more suitable option.
# app/views/posts/_form.html.erb # ... <%= form.fields_for :active_fields, post.initialize_active_values.sort_by(&:active_field_id), include_id: false do |active_fields_form| %> <%= active_fields_form.hidden_field :name %> <%= render_active_value_input(form: active_fields_form, active_value: active_fields_form.object) %> <% end %> # ...
Finally, permit the Active Fields attributes in your Customizables controllers:
# app/controllers/posts_controller.rb # ... def post_params permitted_params = params.require(:post).permit( # ... active_fields_attributes: [:name, :value, :_destroy, value: []], ) permitted_params[:active_fields_attributes]&.each do |_index, value_attrs| value_attrs[:value] = compact_array_param(value_attrs[:value]) if value_attrs[:value].is_a?(Array) end permitted_params end # Removes an empty string from the beginning of the array parameter def compact_array_param(value) if value.first == "" value[1..-1] else value end end
Note: Here we use the
active_fields_attributes=
method (as a permitted parameter),
that integrates well with Railsfields_for
to generate appropriate form fields.
Alternatively, the aliasactive_fields=
can be used in contexts withoutfields_for
, such as API controllers.That's it!
You can now add Active Fields to Customizables athttp://localhost:3000/active_fields
and fill in Active Values within Customizable forms.You can also explore the Demo app
where the plugin is fully integrated into a full-stack Rails application.
Feel free to explore the source code and run it locally:
spec/dummy/bin/setup bin/rails s
-
You can find more information and configuration options on GitHub.
Top comments (0)