class Hanami::Helpers::FormHelper::FormBuilder

Form builder

@since 0.2.0

@see Hanami::Helpers::HtmlHelper::HtmlBuilder

Constants

ACCEPT_SEPARATOR

Separator for accept attribute of file input

@since 0.2.0 @api private

@see Hanami::Helpers::FormHelper::FormBuilder#file_input

BROWSER_METHODS

Set of HTTP methods that are understood by web browsers

@since 0.2.0 @api private

CHECKED

Checked attribute value

@since 0.2.0 @api private

@see Hanami::Helpers::FormHelper::FormBuilder#radio_button

DEFAULT_CHECKED_VALUE

Default value for checked check box

@since 0.2.0 @api private

@see Hanami::Helpers::FormHelper::FormBuilder#check_box

DEFAULT_UNCHECKED_VALUE

Default value for unchecked check box

@since 0.2.0 @api private

@see Hanami::Helpers::FormHelper::FormBuilder#check_box

EXCLUDED_CSRF_METHODS

Set of HTTP methods that should NOT generate CSRF token

@since 0.2.0 @api private

INPUT_ID_REPLACEMENT

Replacement for input id interpolation

@since 0.2.0 @api private

@see Hanami::Helpers::FormHelper::FormBuilder#_input_id

SELECTED

Selected attribute value for option

@since 0.2.0 @api private

@see Hanami::Helpers::FormHelper::FormBuilder#select

Public Class Methods

new(form, attributes, context = nil, params = nil, &blk) click to toggle source

Instantiate a form builder

@overload initialize(form, attributes, context, params, &blk)

Top level form
@param form [Hanami::Helpers:FormHelper::Form] the form
@param attributes [::Hash] a set of HTML attributes
@param context [Hanami::Helpers::FormHelper]
@param params [Hash] optional set of params to override the ones that are coming from the view context
@param blk [Proc] a block that describes the contents of the form

@overload initialize(form, attributes, params, &blk)

Nested form
@param form [Hanami::Helpers:FormHelper::Form] the form
@param attributes [Hanami::Helpers::FormHelper::Values] user defined
  values
@param blk [Proc] a block that describes the contents of the form

@return [Hanami::Helpers::FormHelper::FormBuilder] the form builder

@since 0.2.0 @api private

# File lib/hanami/helpers/form_helper/form_builder.rb, line 103
def initialize(form, attributes, context = nil, params = nil, &blk) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  super()

  @context    = context
  @blk        = blk
  @verb       = nil
  @csrf_token = nil

  # Nested form
  if @context.nil? && attributes.is_a?(Values)
    @values      = attributes
    @attributes  = {}
    @name        = form
  else
    @form        = form
    @name        = form.name
    @values      = Values.new(form.values, params || @context.params)
    @attributes  = attributes
    @verb_method = verb_method
    @csrf_token  = csrf_token
  end
end

Public Instance Methods

button(content, attributes = {}, &blk) click to toggle source

Button

@overload button(content, attributes = {})

Use string content
@param content [String] The content
@param attributes [Hash] HTML attributes to pass to the button tag

@overload button(attributes = {}, &blk)

Use block content
@param attributes [Hash] HTML attributes to pass to the button tag
@param blk [Proc] the block content

@since 1.0.0

@example Basic usage

<%=
  # ...
  button 'Click me'
%>

<!-- output -->
<button>Click me</button>

@example HTML Attributes

<%=
  # ...
  button 'Click me', class: "btn btn-secondary"
%>

<!-- output -->
<button class="btn btn-secondary">Click me</button>

@example Block

<%=
  # ...
  button class: "btn btn-secondary" do
    span class: 'oi oi-check'
  end
%>

<!-- output -->
<button class="btn btn-secondary">
  <span class="oi oi-check"></span>
</button>
Calls superclass method
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1443
def button(content, attributes = {}, &blk)
  if content.is_a?(::Hash)
    attributes = content
    content = nil
  end

  super
end
check_box(name, attributes = {}) click to toggle source

Check box

It renders a check box input.

When a form is submitted, browsers don't send the value of unchecked check boxes. If an user unchecks a check box, their browser won't send the unchecked value. On the server side the corresponding value is missing, so the application will assume that the user action never happened.

To solve this problem the form renders a hidden field with the “unchecked value”. When the user unchecks the input, the browser will ignore it, but it will still send the value of the hidden input. See the examples below.

When editing a resource, the form automatically assigns the checked="checked" attribute.

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag @option attributes [String] :checked_value (defaults to “1”) @option attributes [String] :unchecked_value (defaults to “0”)

@since 0.2.0

@example Basic usage

<%=
  check_box :free_shipping
%>

<!-- output -->
<input type="hidden" name="delivery[free_shipping]" value="0">
<input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="1">

@example HTML Attributes

<%=
  check_box :free_shipping, class: "form-check-input"
%>

<!-- output -->
<input type="hidden" name="delivery[free_shipping]" value="0">
<input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="1" class="form-check-input">

@example Specify (un)checked values

<%=
  check_box :free_shipping, checked_value: 'true', unchecked_value: 'false'
%>

<!-- output -->
<input type="hidden" name="delivery[free_shipping]" value="false">
<input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="true">

@example Automatic “checked” attribute

# For this example the params are:
#
#  { delivery: { free_shipping: '1' } }
<%=
  check_box :free_shipping
%>

<!-- output -->
<input type="hidden" name="delivery[free_shipping]" value="0">
<input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="1" checked="checked">

@example Force “checked” attribute

# For this example the params are:
#
#  { delivery: { free_shipping: '0' } }
<%=
  check_box :free_shipping, checked: 'checked'
%>

<!-- output -->
<input type="hidden" name="delivery[free_shipping]" value="0">
<input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="1" checked="checked">

@example Multiple check boxes

<%=
  check_box :languages, name: 'book[languages][]', value: 'italian', id: nil
  check_box :languages, name: 'book[languages][]', value: 'english', id: nil
%>

<!-- output -->
<input type="checkbox" name="book[languages][]" value="italian">
<input type="checkbox" name="book[languages][]" value="english">

@example Automatic “checked” attribute for multiple check boxes

# For this example the params are:
#
#  { book: { languages: ['italian'] } }
<%=
  check_box :languages, name: 'book[languages][]', value: 'italian', id: nil
  check_box :languages, name: 'book[languages][]', value: 'english', id: nil
%>

<!-- output -->
<input type="checkbox" name="book[languages][]" value="italian" checked="checked">
<input type="checkbox" name="book[languages][]" value="english">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 523
def check_box(name, attributes = {})
  _hidden_field_for_check_box(name, attributes)
  input _attributes_for_check_box(name, attributes)
end
color_field(name, attributes = {}) click to toggle source

Color input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  color_field :background
%>

<!-- output -->
<input type="color" name="user[background]" id="user-background" value="">

@example HTML Attributes

<%=
  # ...
  color_field :background, class: "form-control"
%>

<!-- output -->
<input type="color" name="user[background]" id="user-background" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 552
def color_field(name, attributes = {})
  input _attributes(:color, name, attributes)
end
datalist(name, values, list, attributes = {}) click to toggle source

Datalist input

@param name [Symbol] the input name @param values [Array,Hash] a collection that is transformed into <option> tags. @param list [String] the name of list for the text input, it's also the id of datalist @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.4.0

@example Basic Usage

<%=
  # ...
  values = ['Italy', 'United States']
  datalist :stores, values, 'books'
%>

<!-- output -->
<input type="text" name="book[store]" id="book-store" value="" list="books">
<datalist id="books">
  <option value="Italy"></option>
  <option value="United States"></option>
</datalist>

@example Options As Hash

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  datalist :stores, values, 'books'
%>

<!-- output -->
<input type="text" name="book[store]" id="book-store" value="" list="books">
<datalist id="books">
  <option value="Italy">it</option>
  <option value="United States">us</option>
</datalist>

@example Specify Custom Attributes For Datalist Input

<%=
  # ...
  values = ['Italy', 'United States']
  datalist :stores, values, 'books', datalist: { class: 'form-control' }
%>

<!-- output -->
<input type="text" name="book[store]" id="book-store" value="" list="books">
<datalist id="books" class="form-control">
  <option value="Italy"></option>
  <option value="United States"></option>
</datalist>

@example Specify Custom Attributes For Options List

<%=
  # ...
  values = ['Italy', 'United States']
  datalist :stores, values, 'books', options: { class: 'form-control' }
%>

<!-- output -->
<input type="text" name="book[store]" id="book-store" value="" list="books">
<datalist id="books">
  <option value="Italy" class="form-control"></option>
  <option value="United States" class="form-control"></option>
</datalist>
Calls superclass method
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1383
def datalist(name, values, list, attributes = {}) # rubocop:disable Metrics/MethodLength
  attrs    = attributes.dup
  options  = attrs.delete(:options)  || {}
  datalist = attrs.delete(:datalist) || {}

  attrs[:list]  = list
  datalist[:id] = list

  text_field(name, attrs)
  super(datalist) do
    values.each do |value, content|
      option(content, { value: value }.merge(options))
    end
  end
end
date_field(name, attributes = {}) click to toggle source

Date input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  date_field :birth_date
%>

<!-- output -->
<input type="date" name="user[birth_date]" id="user-birth-date" value="">

@example HTML Attributes

<%=
  # ...
  date_field :birth_date, class: "form-control"
%>

<!-- output -->
<input type="date" name="user[birth_date]" id="user-birth-date" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 580
def date_field(name, attributes = {})
  input _attributes(:date, name, attributes)
end
datetime_field(name, attributes = {}) click to toggle source

Datetime input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  datetime_field :delivered_at
%>

<!-- output -->
<input type="datetime" name="delivery[delivered_at]" id="delivery-delivered-at" value="">

@example HTML Attributes

<%=
  # ...
  datetime_field :delivered_at, class: "form-control"
%>

<!-- output -->
<input type="datetime" name="delivery[delivered_at]" id="delivery-delivered-at" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 608
def datetime_field(name, attributes = {})
  input _attributes(:datetime, name, attributes)
end
datetime_local_field(name, attributes = {}) click to toggle source

Datetime Local input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  datetime_local_field :delivered_at
%>

<!-- output -->
<input type="datetime-local" name="delivery[delivered_at]" id="delivery-delivered-at" value="">

@example HTML Attributes

<%=
  # ...
  datetime_local_field :delivered_at, class: "form-control"
%>

<!-- output -->
<input type="datetime-local" name="delivery[delivered_at]" id="delivery-delivered-at" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 636
def datetime_local_field(name, attributes = {})
  input _attributes(:'datetime-local', name, attributes)
end
email_field(name, attributes = {}) click to toggle source

Email input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  email_field :email
%>

<!-- output -->
<input type="email" name="user[email]" id="user-email" value="">

@example HTML Attributes

<%=
  # ...
  email_field :email, class: "form-control"
%>

<!-- output -->
<input type="email" name="user[email]" id="user-email" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 748
def email_field(name, attributes = {})
  input _attributes(:email, name, attributes)
end
fields_for(name, value = nil) { |name, value| ... } click to toggle source

Nested fields

The inputs generated by the wrapped block will be prefixed with the given name It supports infinite levels of nesting.

@param name [Symbol] the nested name, it's used to generate input

names, ids, and to lookup params to fill values.

@yield [index] @yieldparam [Integer] index iterative index (it starts from zero)

@since 0.2.0

@example Basic usage

<%=
  form_for :delivery, routes.deliveries_path do
    text_field :customer_name

    fields_for :address do
      text_field :street
    end

    submit 'Create'
  end
%>

<!-- output -->
<form action="/deliveries" method="POST" accept-charset="utf-8" id="delivery-form">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <input type="text" name="delivery[customer_name]" id="delivery-customer-name" value="">
  <input type="text" name="delivery[address][street]" id="delivery-address-street" value="">

  <button type="submit">Create</button>
</form>

@example Multiple levels of nesting

<%=
  form_for :delivery, routes.deliveries_path do
    text_field :customer_name

    fields_for :address do
      text_field :street

      fields_for :location do
        text_field :city
        text_field :country
      end
    end

    submit 'Create'
  end
%>

<!-- output -->
<form action="/deliveries" method="POST" accept-charset="utf-8" id="delivery-form">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <input type="text" name="delivery[customer_name]" id="delivery-customer-name" value="">
  <input type="text" name="delivery[address][street]" id="delivery-address-street" value="">
  <input type="text" name="delivery[address][location][city]" id="delivery-address-location-city" value="">
  <input type="text" name="delivery[address][location][country]" id="delivery-address-location-country" value="">

  <button type="submit">Create</button>
</form>
# File lib/hanami/helpers/form_helper/form_builder.rb, line 207
def fields_for(name, value = nil)
  current_name = @name
  @name        = _input_name(name)
  yield(name, value)
ensure
  @name = current_name
end
fields_for_collection(name, &block) click to toggle source

Nested collections

Supports nesting for collections, with infinite levels of nesting.

@param name [Symbol] the nested name, it's used to generate input

names, ids, and to lookup params to fill values.

@yield [index, value] @yieldparam [Integer] index iterative index (it starts from zero) @yieldparam [Object] value an item of the collection

@example Basic usage

<%=
  form_for :delivery, routes.deliveries_path do
    text_field :customer_name

    fields_for_collection :addresses do
      text_field :street
    end

    submit 'Create'
  end
%>

<!-- output -->
<form action="/deliveries" method="POST" accept-charset="utf-8" id="delivery-form">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <input type="text" name="delivery[customer_name]" id="delivery-customer-name" value="">
  <input type="text" name="delivery[addresses][][street]" id="delivery-address-0-street" value="">
  <input type="text" name="delivery[addresses][][street]" id="delivery-address-1-street" value="">

  <button type="submit">Create</button>
</form>

@example Yield index and value

<%=
  form_for(:bill, routes.bill_path(id: bill.id), { bill: bill }, method: :patch, class: 'form-horizontal') do
    fieldset do
      legend "Addresses"

      fields_for_collection :addresses do |i, address|
        div class: "form-group" do
          text "Address id: #{address.id}"

          label :street
          input_text :street, class: "form-control", placeholder: "Street", "data-funky": "index-#{i}"
        end
      end

      label :ensure_names
    end

    submit submit_label, class: "btn btn-default"
  end
%>

<!-- output -->
<form action="/bills/1" method="POST" accept-charset="utf-8" id="bill-form" class="form-horizontal">
  <input type="hidden" name="_method" value="PATCH">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <fieldset>
    <legend>Addresses</legend>

    <div class="form-group">
      Address id: 23
      <label for="bill-addresses-0-street">Street</label>
      <input type="text" name="bill[addresses][][street]" id="bill-addresses-0-street" value="5th Ave" class="form-control" placeholder="Street" data-funky="index-0">
    </div>

    <div class="form-group">
      Address id: 42
      <label for="bill-addresses-1-street">Street</label>
      <input type="text" name="bill[addresses][][street]" id="bill-addresses-1-street" value="4th Ave" class="form-control" placeholder="Street" data-funky="index-1">
    </div>

    <label for="bill-ensure-names">Ensure names</label>
  </fieldset>

  <button type="submit" class="btn btn-default">Update</button>
</form>
# File lib/hanami/helpers/form_helper/form_builder.rb, line 296
def fields_for_collection(name, &block)
  current_name = @name
  base_value = _value(name)
  @name = _input_name(name)

  base_value.each_with_index do |value, index|
    fields_for(index, value, &block)
  end
ensure
  @name = current_name
end
fieldset(content = nil, attributes = {}) click to toggle source

Fieldset

@param content [Symbol,String,NilClass] the content @param attributes [Hash] HTML attributes to pass to the label tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  fieldset do
    legend "Author"

    fields_for :author do
      label :name
      text_field :name
    end
  end
%>

<!-- output -->
<fieldset>
  <legend>Author</legend>
  <label for="book-author-name">Name</label>
  <input type="text" name="book[author][name]" id="book-author-name" value="">
</fieldset>
Calls superclass method
# File lib/hanami/helpers/form_helper/form_builder.rb, line 420
def fieldset(content = nil, attributes = {})
  # This is here only for documentation purposes
  super
end
file_field(name, attributes = {}) click to toggle source

File input

**PLEASE REMEMBER TO ADD enctype: 'multipart/form-data' ATTRIBUTE TO THE FORM**

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag @option attributes [String,Array] :accept Optional set of accepted MIME Types @option attributes [TrueClass,FalseClass] :multiple Optional, allow multiple file upload

@since 0.2.0

@example Basic usage

<%=
  # ...
  file_field :avatar
%>

<!-- output -->
<input type="file" name="user[avatar]" id="user-avatar">

@example HTML Attributes

<%=
  # ...
  file_field :avatar, class: "avatar-upload"
%>

<!-- output -->
<input type="file" name="user[avatar]" id="user-avatar" class="avatar-upload">

@example Accepted MIME Types

<%=
  # ...
  file_field :resume, accept: 'application/pdf,application/ms-word'
%>

<!-- output -->
<input type="file" name="user[resume]" id="user-resume" accept="application/pdf,application/ms-word">

@example Accepted MIME Types (as array)

<%=
  # ...
  file_field :resume, accept: ['application/pdf', 'application/ms-word']
%>

<!-- output -->
<input type="file" name="user[resume]" id="user-resume" accept="application/pdf,application/ms-word">

@example Accepted multiple file upload (as array)

<%=
  # ...
  file_field :resume, multiple: true
%>

<!-- output -->
<input type="file" name="user[resume]" id="user-resume" multiple="multiple">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 885
def file_field(name, attributes = {})
  attributes[:accept] = Array(attributes[:accept]).join(ACCEPT_SEPARATOR) if attributes.key?(:accept)
  attributes = { type: :file, name: _displayed_input_name(name), id: _input_id(name) }.merge(attributes)

  input(attributes)
end
hidden_field(name, attributes = {}) click to toggle source

Hidden input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  hidden_field :customer_id
%>

<!-- output -->
<input type="hidden" name="delivery[customer_id]" id="delivery-customer-id" value="">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 826
def hidden_field(name, attributes = {})
  input _attributes(:hidden, name, attributes)
end
image_button(source, attributes = {}) click to toggle source

Image button

Visual submit button

**Please note:** for security reasons, please use the absolute URL of the image

@param source [String] The **absolute URL** of the image @param attributes [Hash] HTML attributes to pass to the button tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  image_button "https://hanamirb.org/assets/button.png"
%>

<!-- output -->
<input type="image" src="https://hanamirb.org/assets/button.png">

@example HTML Attributes

<%=
  # ...
  image_button "https://hanamirb.org/assets/button.png", name: "image", width: "50"
%>

<!-- output -->
<input name="image" width="50" type="image" src="https://hanamirb.org/assets/button.png">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1480
def image_button(source, attributes = {})
  attrs = attributes.dup
  attrs[:type] = :image
  attrs[:src]  = escape_url(source)

  input attrs
end
input_text(name, attributes = {})
Alias for: text_field
label(content = nil, **attributes, &blk) click to toggle source

Label tag

The first param content can be a Symbol that represents the target field (Eg. :extended_title), or a String which is used as it is.

@param content [Symbol,String] the field name or a content string @param attributes [Hash] HTML attributes to pass to the label tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  label :extended_title
%>

<!-- output -->
<label for="book-extended-title">Extended title</label>

@example HTML attributes

<%=
  # ...
  label :title, class: "form-label"
%>

<!-- output -->
<label for="book-title" class="form-label">Title</label>

@example Custom content

<%=
  # ...
  label 'Title', for: :extended_title
%>

<!-- output -->
<label for="book-extended-title">Title</label>

@example Custom “for” attribute

<%=
  # ...
  label :extended_title, for: 'ext-title'
%>

<!-- output -->
<label for="ext-title">Extended title</label>

@example Nested fields usage

<%=
  # ...
  fields_for :address do
    label :city
    text_field :city
  end
%>

<!-- output -->
<label for="delivery-address-city">City</label>
<input type="text" name="delivery[address][city] id="delivery-address-city" value="">

@example Block syntax

<%=
  # ...
  label for: :free_shipping do
    text "Free shipping"
    abbr "*", title: "optional", "aria-label": "optional"
  end
%>

<!-- output -->
<label for="book-free-shipping">
  Free Shipping
  <abbr title="optional" aria-label="optional">*</abbr>
</label>
Calls superclass method
# File lib/hanami/helpers/form_helper/form_builder.rb, line 382
def label(content = nil, **attributes, &blk)
  attributes = { for: _for(content, attributes.delete(:for)) }.merge(attributes)
  content    = case content
               when String, Hanami::Utils::String, NilClass
                 content
               else
                 Utils::String.capitalize(content)
               end

  super(content, attributes, &blk)
end
month_field(name, attributes = {}) click to toggle source

Month field

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  month_field :release_month
%>

<!-- output -->
<input type="month" name="book[release_month]" id="book-release-month" value="">

@example HTML Attributes

<%=
  # ...
  month_field :release_month, class: "form-control"
%>

<!-- output -->
<input type="month" name="book[release_month]" id="book-release-month" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 692
def month_field(name, attributes = {})
  input _attributes(:month, name, attributes)
end
number_field(name, attributes = {}) click to toggle source

Number input

You can also make use of the `max`, `min`, and `step` attributes for the HTML5 number field.

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the number input

@example Basic usage

<%=
  # ...
  number_field :percent_read
%>

<!-- output -->
<input type="number" name="book[percent_read]" id="book-percent-read" value="">

@example Advanced attributes

<%=
  # ...
  number_field :priority, min: 1, max: 10, step: 1
%>

<!-- output -->
<input type="number" name="book[percent_read]" id="book-precent-read" value="" min="1" max="10" step="1">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 917
def number_field(name, attributes = {})
  input _attributes(:number, name, attributes)
end
password_field(name, attributes = {}) click to toggle source

Password input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  password_field :password
%>

<!-- output -->
<input type="password" name="signup[password]" id="signup-password" value="">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1142
def password_field(name, attributes = {})
  input({ type: :password, name: _displayed_input_name(name), id: _input_id(name), value: nil }.merge(attributes))
end
radio_button(name, value, attributes = {}) click to toggle source

Radio input

If request params have a value that corresponds to the given value, it automatically sets the checked attribute. This Hanami::Controller integration happens without any developer intervention.

@param name [Symbol] the input name @param value [String] the input value @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  radio_button :category, 'Fiction'
  radio_button :category, 'Non-Fiction'
%>

<!-- output -->
<input type="radio" name="book[category]" value="Fiction">
<input type="radio" name="book[category]" value="Non-Fiction">

@example HTML Attributes

<%=
  # ...
  radio_button :category, 'Fiction', class: "form-check"
  radio_button :category, 'Non-Fiction', class: "form-check"
%>

<!-- output -->
<input type="radio" name="book[category]" value="Fiction" class="form-check">
<input type="radio" name="book[category]" value="Non-Fiction" class="form-check">

@example Automatic checked value

# Given the following params:
#
# book: {
#   category: 'Non-Fiction'
# }

<%=
  # ...
  radio_button :category, 'Fiction'
  radio_button :category, 'Non-Fiction'
%>

<!-- output -->
<input type="radio" name="book[category]" value="Fiction">
<input type="radio" name="book[category]" value="Non-Fiction" checked="checked">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1121
def radio_button(name, value, attributes = {})
  attributes = { type: :radio, name: _displayed_input_name(name), value: value }.merge(attributes)
  attributes[:checked] = CHECKED if _value(name).to_s == value.to_s
  input(attributes)
end
range_field(name, attributes = {}) click to toggle source

Range input

You can also make use of the `max`, `min`, and `step` attributes for the HTML5 number field.

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the number input

@since 1.0.0

@example Basic usage

<%=
  # ...
  range_field :discount_percentage
%>

<!-- output -->
<input type="range" name="book[discount_percentage]" id="book-discount-percentage" value="">

@example Advanced attributes

<%=
  # ...
  range_field :discount_percentage, min: 1, max: 10, step: 1
%>

<!-- output -->
<input type="number" name="book[discount_percentage]" id="book-discount-percentage" value="" min="1" max="10" step="1">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 948
def range_field(name, attributes = {})
  input _attributes(:range, name, attributes)
end
search_field(name, attributes = {}) click to toggle source

Search input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  search_field :q
%>

<!-- output -->
<input type="search" name="search[q]" id="search-q" value="">

@example HTML Attributes

<%=
  # ...
  search_field :q, class: "form-control"
%>

<!-- output -->
<input type="search" name="search[q]" id="search-q" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1067
def search_field(name, attributes = {})
  input _attributes(:search, name, attributes)
end
select(name, values, attributes = {}) click to toggle source

Select input

@param name [Symbol] the input name @param values [Hash] a Hash to generate <option> tags. @param attributes [Hash] HTML attributes to pass to the input tag

Values is used to generate the list of &lt;option&gt; tags, it is an Enumerable of pairs of content (the displayed text) and value (the tag's attribute), in that respective order (please refer to the examples for more clarity).

If request params have a value that corresponds to one of the given values, it automatically sets the selected attribute on the <option> tag. This Hanami::Controller integration happens without any developer intervention.

@since 0.2.0

@example Basic usage

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :store, values
%>

<!-- output -->
<select name="book[store]" id="book-store">
  <option value="it">Italy</option>
  <option value="us">United States</option>
</select>

@example HTML Attributes

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :store, values, class: "form-control"
%>

<!-- output -->
<select name="book[store]" id="book-store" class="form-control">
  <option value="it">Italy</option>
  <option value="us">United States</option>
</select>

@example Automatic selected option

# Given the following params:
#
# book: {
#   store: 'it'
# }

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :store, values
%>

<!-- output -->
<select name="book[store]" id="book-store">
  <option value="it" selected="selected">Italy</option>
  <option value="us">United States</option>
</select>

@example Prompt option

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :store, values, options: { prompt: 'Select a store' }
%>

<!-- output -->
<select name="book[store]" id="book-store">
  <option>Select a store</option>
  <option value="it">Italy</option>
  <option value="us">United States</option>
</select>

@example Selected option

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :store, values, options: { selected: book.store }
%>

<!-- output -->
<select name="book[store]" id="book-store">
  <option value="it" selected="selected">Italy</option>
  <option value="us">United States</option>
</select>

@example Prompt option and HTML attributes

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :store, values, options: { prompt: 'Select a store' }, class: "form-control"
%>

<!-- output -->
<select name="book[store]" id="book-store" class="form-control">
  <option disabled="disabled">Select a store</option>
  <option value="it">Italy</option>
  <option value="us">United States</option>
</select>

@example Multiple select

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :stores, values, multiple: true
%>

<!-- output -->
<select name="book[store][]" id="book-store" multiple="multiple">
 <option value="it">Italy</option>
  <option value="us">United States</option>
</select>

@example Multiple select and HTML attributes

<%=
  # ...
  values = Hash['Italy' => 'it', 'United States' => 'us']
  select :stores, values, multiple: true, class: "form-control"
%>

<!-- output -->
<select name="book[store][]" id="book-store" multiple="multiple" class="form-control">
  <option value="it">Italy</option>
  <option value="us">United States</option>
</select>

@example Array with repeated entries

<%=
  # ...
  values = [['Italy', 'it'],
            ['---', ''],
            ['Afghanistan', 'af'],
            ...
            ['Italy', 'it'],
            ...
            ['Zimbabwe', 'zw']]
  select :stores, values
%>

<!-- output -->
<select name="book[store]" id="book-store">
  <option value="it">Italy</option>
  <option value="">---</option>
  <option value="af">Afghanistan</option>
  ...
  <option value="it">Italy</option>
  ...
  <option value="zw">Zimbabwe</option>
</select>
Calls superclass method
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1297
def select(name, values, attributes = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  options     = attributes.delete(:options) { {} }
  multiple    = attributes[:multiple]
  attributes  = { name: _select_input_name(name, multiple), id: _input_id(name) }.merge(attributes)
  prompt      = options.delete(:prompt)
  selected    = options.delete(:selected)
  input_value = _value(name)

  super(attributes) do
    option(prompt, disabled: true) if prompt

    already_selected = nil
    values.each do |content, value|
      if (multiple || !already_selected) && (already_selected = _select_option_selected?(value, selected, input_value, multiple))
        option(content, { value: value, selected: SELECTED }.merge(options))
      else
        option(content, { value: value }.merge(options))
      end
    end
  end
end
submit(content, attributes = {}, &blk) click to toggle source

Submit button

@overload submit(content, attributes = {})

Use string content
@param content [String] The content
@param attributes [Hash] HTML attributes to pass to the button tag

@overload submit(attributes = {}, &blk)

Use block content
@param attributes [Hash] HTML attributes to pass to the button tag
@param blk [Proc] the block content

@since 0.2.0

@example Basic usage

<%=
  # ...
  submit 'Create'
%>

<!-- output -->
<button type="submit">Create</button>

@example HTML Attributes

<%=
  # ...
  submit 'Create', class: "btn btn-primary"
%>

<!-- output -->
<button type="submit" class="btn btn-primary">Create</button>

@example Block

<%=
  # ...
  button class: "btn btn-primary" do
    span class: 'oi oi-check'
  end
%>

<!-- output -->
<button type="submit" class="btn btn-primary">
  <span class="oi oi-check"></span>
</button>
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1532
def submit(content, attributes = {}, &blk)
  if content.is_a?(::Hash)
    attributes = content
    content = nil
  end

  attributes = { type: :submit }.merge(attributes)
  button(content, attributes, &blk)
end
tel_field(name, attributes = {}) click to toggle source

Telephone input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  tel_field :telephone
%>

<!-- output -->
<input type="tel" name="user[telephone]" id="user-telephone" value="">

@example HTML Attributes

<%=
  # ...
  telurl_field :telephone, class: "form-control"
%>

<!-- output -->
<input type="tel" name="user[telephone]" id="user-telephone" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 807
def tel_field(name, attributes = {})
  input _attributes(:tel, name, attributes)
end
text_area(name, content = nil, attributes = {}) click to toggle source

Text-area input

@param name [Symbol] the input name @param content [String] the content of the textarea @param attributes [Hash] HTML attributes to pass to the textarea tag

@since 0.2.5

@example Basic usage

<%=
  # ...
  text_area :hobby
%>

<!-- output -->
<textarea name="user[hobby]" id="user-hobby"></textarea>

@example Set content

<%=
  # ...
  text_area :hobby, 'Football'
%>

<!-- output -->
<textarea name="user[hobby]" id="user-hobby">Football</textarea>

@example Set content and HTML attributes

<%=
  # ...
  text_area :hobby, 'Football', class: 'form-control'
%>

<!-- output -->
<textarea name="user[hobby]" id="user-hobby" class="form-control">Football</textarea>

@example Omit content and specify HTML attributes

<%=
  # ...
  text_area :hobby, class: 'form-control'
%>

<!-- output -->
<textarea name="user[hobby]" id="user-hobby" class="form-control"></textarea>

@example Force blank value

<%=
  # ...
  text_area :hobby, '', class: 'form-control'
%>

<!-- output -->
<textarea name="user[hobby]" id="user-hobby" class="form-control"></textarea>
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1004
def text_area(name, content = nil, attributes = {})
  if content.respond_to?(:to_hash)
    attributes = content
    content    = nil
  end

  attributes = { name: _displayed_input_name(name), id: _input_id(name) }.merge(attributes)
  textarea(content || _value(name), attributes)
end
text_field(name, attributes = {}) click to toggle source

Text input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 0.2.0

@example Basic usage

<%=
  # ...
  text_field :first_name
%>

<!-- output -->
<input type="text" name="user[first_name]" id="user-first-name" value="">

@example HTML Attributes

<%=
  # ...
  text_field :first_name, class: "form-control"
%>

<!-- output -->
<input type="text" name="user[first_name]" id="user-first-name" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 1038
def text_field(name, attributes = {})
  input _attributes(:text, name, attributes)
end
Also aliased as: input_text
time_field(name, attributes = {}) click to toggle source

Time field

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  time_field :release_hour
%>

<!-- output -->
<input type="time" name="book[release_hour]" id="book-release-hour" value="">

@example HTML Attributes

<%=
  # ...
  time_field :release_hour, class: "form-control"
%>

<!-- output -->
<input type="time" name="book[release_hour]" id="book-release-hour" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 664
def time_field(name, attributes = {})
  input _attributes(:time, name, attributes)
end
to_s() click to toggle source

Resolves all the nodes and generates the markup

@return [Hanami::Utils::Escape::SafeString] the output

@since 0.2.0 @api private

@see Hanami::Helpers::HtmlHelper::HtmlBuilder#to_s @see www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Escape/SafeString

# File lib/hanami/helpers/form_helper/form_builder.rb, line 135
def to_s
  if toplevel?
    _method_override!
    form(@blk, @attributes)
  end

  super
end
url_field(name, attributes = {}) click to toggle source

URL input

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  url_field :website
%>

<!-- output -->
<input type="url" name="user[website]" id="user-website" value="">

@example HTML Attributes

<%=
  # ...
  url_field :website, class: "form-control"
%>

<!-- output -->
<input type="url" name="user[website]" id="user-website" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 776
def url_field(name, attributes = {})
  attrs         = attributes.dup
  attrs[:value] = escape_url(attrs.fetch(:value) { _value(name) })

  input _attributes(:url, name, attrs)
end
week_field(name, attributes = {}) click to toggle source

Week field

@param name [Symbol] the input name @param attributes [Hash] HTML attributes to pass to the input tag

@since 1.0.0

@example Basic usage

<%=
  # ...
  week_field :release_week
%>

<!-- output -->
<input type="week" name="book[release_week]" id="book-release-week" value="">

@example HTML Attributes

<%=
  # ...
  week_field :release_week, class: "form-control"
%>

<!-- output -->
<input type="week" name="book[release_week]" id="book-release-week" value="" class="form-control">
# File lib/hanami/helpers/form_helper/form_builder.rb, line 720
def week_field(name, attributes = {})
  input _attributes(:week, name, attributes)
end

Protected Instance Methods

options() click to toggle source

A set of options to pass to the sub form helpers.

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1548
def options
  Hash[name: @name, values: @values, verb: @verb, csrf_token: @csrf_token]
end

Private Instance Methods

_attributes(type, name, attributes) click to toggle source

Return a set of default HTML attributes

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1594
def _attributes(type, name, attributes)
  attrs = { type: type, name: _displayed_input_name(name), id: _input_id(name), value: _value(name) }
  attrs.merge!(attributes)
  attrs[:value] = escape_html(attrs[:value])
  attrs
end
_attributes_for_check_box(name, attributes) click to toggle source

HTML attributes for check box

@api private @since 0.2.0

@see Hanami::Helpers::FormHelper::FormBuilder#check_box

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1672
def _attributes_for_check_box(name, attributes)
  attributes = {
    type: :checkbox,
    name: _displayed_input_name(name),
    id: _input_id(name),
    value: attributes.delete(:checked_value) || DEFAULT_CHECKED_VALUE
  }.merge(attributes)

  attributes[:checked] = CHECKED if _check_box_checked?(attributes[:value], _value(name))

  attributes
end
_check_box_checked?(value, input_value) click to toggle source

@api private

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1729
def _check_box_checked?(value, input_value)
  !input_value.nil? &&
    (input_value.to_s == value.to_s || input_value.is_a?(TrueClass) ||
    input_value.is_a?(Array) && input_value.include?(value))
end
_displayed_input_name(name) click to toggle source

Input name HTML attribute

@api private @since 1.0.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1614
def _displayed_input_name(name)
  _input_name(name).gsub(/\[\d+\]/, '[]')
end
_for(content, name) click to toggle source

Input for HTML attribute

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1641
def _for(content, name)
  case name
  when String, Hanami::Utils::String
    name
  else
    _input_id(name || content)
  end
end
_hidden_field_for_check_box(name, attributes) click to toggle source

Hidden field for check box

@api private @since 0.2.0

@see Hanami::Helpers::FormHelper::FormBuilder#check_box

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1656
def _hidden_field_for_check_box(name, attributes)
  return unless attributes[:value].nil? || !attributes[:unchecked_value].nil?

  input(
    type: :hidden,
    name: attributes[:name] || _displayed_input_name(name),
    value: attributes.delete(:unchecked_value) || DEFAULT_UNCHECKED_VALUE
  )
end
_input_id(name) click to toggle source

Input id HTML attribute

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1622
def _input_id(name)
  name = _input_name(name).gsub(/\[(?<token>[[[:word:]]\-]*)\]/, INPUT_ID_REPLACEMENT)
  Utils::String.dasherize(name)
end
_input_name(name) click to toggle source

Full input name, used to construct the input attributes.

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1606
def _input_name(name)
  "#{@name}[#{name}]"
end
_is_current_value?(input_value, value) click to toggle source

@api private @since 1.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1706
def _is_current_value?(input_value, value)
  return unless input_value

  value.to_s == input_value.to_s
end
_is_in_input_values?(multiple, input_value, value) click to toggle source

@api private @since 1.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1722
def _is_in_input_values?(multiple, input_value, value)
  return unless multiple && input_value.is_a?(Array)

  input_value.include?(value)
end
_is_in_selected_values?(multiple, selected, value) click to toggle source

@api private @since 1.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1714
def _is_in_selected_values?(multiple, selected, value)
  return unless multiple && selected.is_a?(Array)

  selected.include?(value)
end
_method_override!() click to toggle source

Prepare for method override

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1566
def _method_override!
  if BROWSER_METHODS.include?(@verb_method)
    @attributes[:method] = @verb_method
  else
    @attributes[:method] = DEFAULT_METHOD
    @verb                = @verb_method
  end
end
_select_input_name(name, multiple) click to toggle source

@api private

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1686
def _select_input_name(name, multiple)
  select_name = _displayed_input_name(name)
  select_name = "#{select_name}[]" if multiple
  select_name
end
_select_option_selected?(value, selected, input_value, multiple) click to toggle source

@api private

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1693
def _select_option_selected?(value, selected, input_value, multiple)
  if input_value && selected.nil?
    value.to_s == input_value.to_s
  else
    (value == selected) ||
      _is_in_selected_values?(multiple, selected, value) ||
      _is_current_value?(input_value, value) ||
      _is_in_input_values?(multiple, input_value, value)
  end
end
_value(name) click to toggle source

Input value HTML attribute

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1631
def _value(name)
  @values.get(
    *_input_name(name).split(/[\[\]]+/).map(&:to_sym)
  )
end
csrf_token() click to toggle source

Return CSRF Protection token from view context

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1586
def csrf_token
  @context.csrf_token if @context.respond_to?(:csrf_token) && !EXCLUDED_CSRF_METHODS.include?(@verb_method)
end
toplevel?() click to toggle source

Check the current builder is top-level

@api private @since 0.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1558
def toplevel?
  @attributes.any?
end
verb_method() click to toggle source

Return the method from attributes

@api private

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1578
def verb_method
  (@attributes.fetch(:method) { DEFAULT_METHOD }).to_s.upcase
end