Fake inputs for formtastic forms

Here I’m going to tell about very small gem I wrote to provide absolute read-only fields for ActiveAdmin’s resource editing page.

We’re using an ActiveAdmin gem to build neat dashboards for one of our projects. Its form generation mechanism is based on a Formtastic gem.

It allows you to describe dashboards in a very simple way using an elegant DSL (check out their website).

Let’s consider the Order entity. In our system Order model is very complicated. It is created and processed by background workers and API calls from external CRM system.

Long story short, among all of its attributes the only one to be occasionally changed is a payment gateway. Normally, it is not set at all and though is automatically selected yet sometimes we need to lock its value.

Ok, but how should we define Order’s edit form? If we keep the only allowed payment_gateway field, the form will look confusing. If we add more fields to clarify the context, they all will look editable, which is not.

The solution is not to use <input> tags for form fields we don’t want users to change! Boyond keeping the form’s clarity it allows us to remove unwanted data from form’s POST request.

This is exactly what my formtastic-fake_input gem is doing.

It introduces new input class you can use in yor forms like this:

<%= semantic_form_for(@user) do |f| %>
  <%= f.inputs do %>
    <%= f.input :id, :as => :fake %>
    <%= f.input :tax_class,  :as => :fake, :value => "Class #{f.object.tax_class}" %>
    <%= f.input :first_name, :as => :string %>
  <% end %>
<% end %>

Notice how we use FakeInput class here by specifying :as => :fake parameter.

Additionally, you can customize the value to be displayed as a field value by setting the :value parameter.

Now we can write ActiveAdmin’s Order editing form:

ActiveAdmin.register Order do
  # ...
  permit_params :payment_gateway_id
  # ...

  form do |f|
    f.semantic_errors
    f.inputs do
      f.input :id, as: :fake
      f.input :request_id, as: :fake, value: order.request_id.presence || '—'
      f.input :created_from, as: :fake
      f.input :legal_entity, as: :fake, value: order.legal_entity&.short_name || '—'
      f.input :payment_gateway, collection: order.legal_entity.payment_gateways
    end
    f.actions
  end
end

Notice the usage of || '—' statement in :value parameter. It allow us to show dashes in case the field value is missing.

And finally, here is how the result form looks:

Form screenshot

And fieldset HTML code:

<fieldset class="inputs">
<ol>
  <li class="fake input optional stringish" id="order_id_input">
    <label for="order_id" class="label">Id</label>
    <span>696baf36-d51c-4e00-84f9-7b00d6cac56b</span>
  </li>
  <li class="fake input optional stringish" id="order_request_id_input">
    <label for="order_request_id" class="label">Request ID</label>
    <span></span>
  </li>
  <li class="fake input optional stringish" id="order_created_from_input">
    <label for="order_created_from" class="label">Created from</label>
    <span>site_tour</span>
  </li>
  <li class="fake input required stringish" id="order_legal_entity_input">
    <label for="order_legal_entity_id" class="label">Legal entity</label>
    <span>Sunflower LLC</span>
  </li>
  <li class="select input optional" id="order_payment_gateway_input">
    <label for="order_payment_gateway_id" class="label">Payment gateway</label>
    <select name="order[payment_gateway_id]" id="order_payment_gateway_id">
      <option value=""></option>
      <option value="1">Gateway 1</option>
      <option value="2">Gateway 2</option>
    </select>
  </li>
</ol>
</fieldset>

Comment

Has something on your mind? Tweet it!