DEV Community

Cover image for Add custom fields to your Rails models with ActiveFields gem
Kirill Usanov
Kirill Usanov

Posted on

Add custom fields to your Rails models with ActiveFields gem

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

  1. Install the gem and add it to your application's Gemfile by running:

    bundle add active_fields
    
  2. Run install generator, then run migrations:

    bin/rails generate active_fields:install
    bin/rails db:migrate
    
  3. Add the has_active_fields method to any models where you want to enable custom fields:

    class Post < ApplicationRecord
      has_active_fields
    end
    
  4. 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.

  5. 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 Rails fields_for to generate appropriate form fields.
    Alternatively, the alias active_fields= can be used in contexts without fields_for, such as API controllers.

    That's it!
    You can now add Active Fields to Customizables at http://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.

Links:
GitHub
RubyGems
EAV Wiki

Top comments (0)