Skip to content

SimpleForm inputs & components

Dylan Fisher edited this page Feb 6, 2024 · 22 revisions

Custom SimpleForm inputs

These custom SimpleForm inputs are available in your form builders by setting an as option.

datepicker_input.rb

Render a date or datetime input using a jQuery UI datepicker.

<%= f.input :date, as: :datepicker %>

timepicker_input.rb

Render a time input using a jQuery timepicker.

Note: this field must be formatted as a datetime object in the database.

<%= f.input :time, as: :timepicker %>

gallery_input.rb

A sortable gallery of Media Items.

rails g forest:block SlideshowBlock

rails g model SlideshowBlockSlide slideshow_block:references media_item:references position:integer

has_many_ordered :media_items, through: :slideshow_block_slides

# slideshow_block_slide.rb
# associations must be set to optional
belongs_to :media_item, optional: true
belongs_to :slideshow_block, optional: true
def self.permitted_params
  [media_item_ids: []]
end

<%= f.association :media_items, as: :gallery, sortable: true %>

image_input.rb

A single image association.

<%= f.association :featured_image, as: :image %>

repeater_input.rb

Create a repeatable set of key, value pairs. These are saved as a serialized array directly on the model. Useful when you don't need a full has_and_belongs_to_many association.

Add a text column where you want to store the repeatable data, for example a column named additional_metadata

Then, in your model:

has_repeatable :additional_metadata

And in your form:

<%= f.input :additional_metadata, as: :repeater %>

Allow the params in your controller:

additional_metadata: [:key, :value]

Use it in your view:

<% @record.additional_metadata.each do |metadata_item| %>
  <div class="metadata__key"><%= metadata_item[:key] %></div>
  <div class="metadata__value"><%= metadata_item[:value] %></div>
<% end %>

collage_input.rb

Create a collage of Media Items that you can drag to rearrange on a resizable canvas.

Generate the block:

rails g forest:block CollageBlock collage_height_ratio:decimal

Generate the associated collage items:

rails g model CollageBlockItem media_item:references collage_block:references collage_position_left:decimal collage_position_top:decimal collage_item_width:decimal collage_item_height:decimal collage_z_index:integer

# collage_block.rb
has_many :collage_block_items, dependent: :destroy
has_many :media_items, through: :collage_block_items

accepts_nested_attributes_for :collage_block_items, allow_destroy: true, reject_if: proc { |attributes| attributes['media_item_id'].blank? }

def collage_canvas_styles
  styles = []
  styles << "height: 0px"
  styles << "padding-bottom: #{collage_height_ratio}%"
  styles.join('; ')
end
# collage_block_item.rb
belongs_to :media_item, optional: true, touch: true
belongs_to :collage_block, optional: true, touch: true

def css_styles
  styles = []
  styles << "width: #{collage_item_width}%"
  styles << "height: #{collage_item_height}%"
  styles << "top: #{collage_position_top}%"
  styles << "left: #{collage_position_left}%"
  styles << "z-index: #{collage_z_index}"
  styles.join('; ')
end

Allow the following params in your controller or block:

:collage_height_ratio, 
collage_block_items_attributes: [
  :id, :_destroy, :media_item_id, :collage_block_id,
  :collage_position_left, :collage_position_top, :collage_z_index, :collage_item_width, :collage_item_height
]
<%# /app/views/blocks/collage_block/_edit.html.erb %>
<%= f.association :collage_block_items, as: :collage %>
<%# /app/views/blocks/collage_block/_show.html.erb %>
<%= content_tag :div, class: 'collage-block__canvas', style: block.collage_canvas_styles do %>
  <% block.collage_block_items.each do |collage_block_item| %>
    <%= content_tag :div, class: 'collage-block__item', style: collage_block_item.css_styles do %>
      <%= image_tag collage_block_item.media_item.attachment.url(:medium), class: 'collage-block__image' %>
    <% end %>
  <% end %>
<% end %>
// Collage Block

.collage-block__canvas {
  position: relative;
}

.collage-block__item {
  position: absolute;
}

If you need to add additional fields to the collage items, you can insert them into the edit view by creating a partial at the following location:

/app/views/blocks/collage_block/_collage_fields.html.erb

If you want to add the ability to insert text to a collage, specify this via the text_box key. The collage input will look for a text attribute on your collage block item. You may specify a different attribute with the text_box_attr option.

<%= f.association :collage_block_items, as: :collage, text_box: true %>

block_selector_input.rb

Add a select input that allows you to choose a block from the current block record.

<%# /app/views/blocks/jump_link_block/_edit.html.erb %>
<%= f.input :anchor, as: :block_selector %>

color_input.rb

Adds a dynamic color picker for choosing a hex color.

<%= f.input :color, as: color %>

Custom SimpleForm components

These custom SimpleForm components are available in your form builders by setting the component option to true.

markdown.rb

Render a text field with a WYSIWYG markdown editor.

<%= f.input :description, markdown: true %>

remote.rb

Render an association that may have many records using an ajax select2 input.

<%= f.association :page, remote: true %>

Explicitly set the ajax path:

<%= f.association :project, remote: { path: admin_projects_path(active: true) } %>

sortable.rb

Create sortable select2 inputs by using a custom ActiveRecord class method:

# project_block.rb

has_many_ordered :projects, through: :project_block_projects
# project_block/_edit.html.erb

<%= f.association :projects, sortable: true, remote: true %>

Form helper patterns

A number of other helper functions are built into the Forest admin. Use the following class names and code patterns to help with some common form behaviors.

State/Country Select

If you have a state and country selection tied to an input, you can use the following markup to toggle the state field selection to only display US states when the USA country is selected.

<%= f.input :state, wrapper_html: { class: 'state-input--text' } %>
<%= f.input :state, as: :select, selected: 'CA', disabled: true, collection: State::US.to_a.collect { |k, v| [v, k] }, wrapper_html: { class: 'state-input--select' } %>
<%= f.input :country, priority: ["USA"] %>

Clone this wiki locally