class Hanami::Helpers::FormHelper::FormBuilder

A range of convenient methods for building the fields within an HTML form, integrating with request params and template locals to populate the fields with appropriate values.

@see FormHelper#form_for

@api public @since 2.1.0

Constants

ACCEPT_SEPARATOR

Separator for accept attribute of file input

@since 2.1.0 @api private

@see file_input

BROWSER_METHODS

Set of HTTP methods that are understood by web browsers

@since 2.1.0 @api private

DEFAULT_CHECKED_VALUE

Default value for checked check box

@since 2.1.0 @api private

@see check_box

DEFAULT_UNCHECKED_VALUE

Default value for unchecked check box

@since 2.1.0 @api private

@see check_box

EMPTY_STRING

Empty string

@since 2.1.0 @api private

@see password_field

EXCLUDED_CSRF_METHODS

Set of HTTP methods that should NOT generate CSRF token

@since 2.1.0 @api private

INPUT_NAME_SEPARATOR

Input name separator

@since 2.1.0 @api private

Attributes

base_name[R]

@api private @since 2.1.0

form_attributes[R]

@api private @since 2.1.0

inflector[R]

@api private @since 2.1.0

values[R]

@api private @since 2.1.0

Public Class Methods

new(inflector:, form_attributes:, base_name: nil, values: Values.new) click to toggle source

Returns a new form builder.

@param inflector [Dry::Inflector] the app inflector @param base_name [String, nil] the base name to use for all fields in the form @param values [Hanami::Helpers::FormHelper::Values] the values for the form

@return [self]

@see Hanami::Helpers::FormHelper#form_for

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 109
def initialize(inflector:, form_attributes:, base_name: nil, values: Values.new)
  @base_name = base_name
  @values = values
  @form_attributes = form_attributes
  @inflector = inflector
end

Public Instance Methods

button(...) click to toggle source

Returns a button tag.

@return [String] the tag

@overload button(content, **attributes)

Returns a button tag with the given content.

@param content [String] the content for the tag
@param attributes [Hash] the tag's HTML attributes

@overload button(**attributes, &block)

Returns a button tag with the return value of the given block as the tag's content.

@param attributes [Hash] the tag's HTML attributes
@yieldreturn [String] the tag content

@example Basic usage

f.button("Click me")
=> <button>Click me</button>

@example HTML Attributes

f.button("Click me", class: "btn btn-secondary")
=> <button class="btn btn-secondary">Click me</button>

@example Returning content from a block

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

=>
<button class="btn btn-secondary">
  <span class="oi oi-check"></span>
</button>

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1123
def button(...)
  tag.button(...)
end
call(content, **attributes) click to toggle source

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 118
def call(content, **attributes)
  attributes["accept-charset"] ||= DEFAULT_CHARSET

  method_override, original_form_method = _form_method(attributes)
  csrf_token, token = _csrf_token(values, attributes)

  tag.form(**attributes) do
    (+"").tap { |inner|
      inner << input(type: "hidden", name: "_method", value: original_form_method) if method_override
      inner << input(type: "hidden", name: "_csrf_token", value: token) if csrf_token
      inner << content
    }.html_safe
  end
end
check_box(name, **attributes) click to toggle source

Returns the tags for a check box.

When editing a resource, the form automatically assigns the ‘checked` HTML attribute for the check box tag.

Returns a hidden input tag in preceding the check box input tag. This ensures that unchecked values are submitted with the form.

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

@return [String] the tags

@example Basic usage

f.check_box("delivery.free_shipping")

# =>
<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

f.check_box("delivery.free_shipping", class: "form-check-input")

=>
<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 Specifying checked and unchecked values

f.check_box("delivery.free_shipping", checked_value: "true", unchecked_value: "false")

=>
<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

# Given the request params:
# {delivery: {free_shipping: "1"}}
f.check_box("delivery.free_shipping")

=>
<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 Forcing the “checked” attribute

# Given the request params:
# {delivery: {free_shipping: "0"}}
f.check_box("deliver.free_shipping", checked: "checked")

=>
<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 for an array of values

f.check_box("book.languages", name: "book[languages][]", value: "italian", id: nil)
f.check_box("book.languages", name: "book[languages][]", value: "english", id: nil)

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

@example Automatic “checked” attribute for an array of values

# Given the request params:
# {book: {languages: ["italian"]}}
f.check_box("book.languages", name: "book[languages][]", value: "italian", id: nil)
f.check_box("book.languages", name: "book[languages][]", value: "english", id: nil)

=>
<input type="checkbox" name="book[languages][]" value="italian" checked="checked">
<input type="checkbox" name="book[languages][]" value="english">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 405
def check_box(name, **attributes)
  (+"").tap { |output|
    output << _hidden_field_for_check_box(name, attributes).to_s
    output << input(**_attributes_for_check_box(name, attributes))
  }.html_safe
end
color_field(name, **attributes) click to toggle source

Returns a color input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.color_field("user.background")
=> <input type="color" name="user[background]" id="user-background" value="">

@example HTML Attributes

f.color_field("user.background", class: "form-control")
=> <input type="color" name="user[background]" id="user-background" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 429
def color_field(name, **attributes)
  input(**_attributes(:color, name, attributes))
end
datalist(name, values, list, **attributes) click to toggle source

Returns a datalist input tag.

@param name [String] 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; also the id of datalist @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic Usage

values = ["Italy", "Australia"]
f.datalist("book.stores", values, "books")

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

@example Options As Hash

values = Hash["Italy" => "it", "Australia" => "au"]
f.datalist("book.stores", values, "books")

=>
<input type="text" name="book[store]" id="book-store" value="" list="books">
<datalist id="books">
  <option value="Italy">it</option>
  <option value="Australia">au</option>
</datalist>

@example Specifying custom attributes for the datalist input

values = ["Italy", "Australia"]
f.datalist "book.stores", values, "books", datalist: {class: "form-control"}

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

@example Specifying custom attributes for the options list

values = ["Italy", "Australia"]
f.datalist("book.stores", values, "books", options: {class: "form-control"})

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

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1068
def datalist(name, values, list, **attributes)
  options = attributes.delete(:options) || {}
  datalist = attributes.delete(:datalist) || {}

  attributes[:list] = list
  datalist[:id] = list

  (+"").tap { |output|
    output << text_field(name, **attributes)
    output << tag.datalist(**datalist) {
      (+"").tap { |inner|
        values.each do |value, content|
          inner << tag.option(content, value: value, **options)
        end
      }.html_safe
    }
  }.html_safe
end
date_field(name, **attributes) click to toggle source

Returns a date input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.date_field("user.birth_date")
# => <input type="date" name="user[birth_date]" id="user-birth-date" value="">

@example HTML Attributes

f.date_field("user.birth_date", class: "form-control")
=> <input type="date" name="user[birth_date]" id="user-birth-date" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 450
def date_field(name, **attributes)
  input(**_attributes(:date, name, attributes))
end
datetime_field(name, **attributes) click to toggle source

Returns a datetime input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.datetime_field("delivery.delivered_at")
=> <input type="datetime" name="delivery[delivered_at]" id="delivery-delivered-at" value="">

@example HTML Attributes

f.datetime_field("delivery.delivered_at", class: "form-control")
=> <input type="datetime" name="delivery[delivered_at]" id="delivery-delivered-at" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 471
def datetime_field(name, **attributes)
  input(**_attributes(:datetime, name, attributes))
end
datetime_local_field(name, **attributes) click to toggle source

Returns a datetime-local input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.datetime_local_field("delivery.delivered_at")
=> <input type="datetime-local" name="delivery[delivered_at]" id="delivery-delivered-at" value="">

@example HTML Attributes

f.datetime_local_field("delivery.delivered_at", class: "form-control")
=> <input type="datetime-local" name="delivery[delivered_at]" id="delivery-delivered-at" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 492
def datetime_local_field(name, **attributes)
  input(**_attributes(:"datetime-local", name, attributes))
end
email_field(name, **attributes) click to toggle source

Returns an email input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.email_field("user.email")
=> <input type="email" name="user[email]" id="user-email" value="">

@example HTML Attributes

f.email_field("user.email", class: "form-control")
=> <input type="email" name="user[email]" id="user-email" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 576
def email_field(name, **attributes)
  input(**_attributes(:email, name, attributes))
end
fields_for(name, *yield_args) { |builder, *yield_args| ... } click to toggle source

Applies the base input name to all fields within the given block.

This can be helpful when generating a set of nested fields.

This is a convenience only. You can achieve the same result by including the base name at the beginning of each input name.

@param name [String] the base name to be used for all fields in the block @yieldparam [FormBuilder] the form builder for the nested fields

@example Basic usage

<% f.fields_for "address" do |fa| %>
  <%= fa.text_field "street" %>
  <%= fa.text_field "suburb" %>
<% end %>

# A convenience for:
# <%= f.text_field "address.street" %>
# <%= f.text_field "address.suburb" %>

=>
<input type="text" name="delivery[customer_name]" id="delivery-customer-name" value="">
<input type="text" name="delivery[address][street]" id="delivery-address-street" value="">

@example Multiple levels of nesting

<% f.fields_for "address" do |fa| %>
  <%= fa.text_field "street" %>

  <% fa.fields_for "location" do |fl| %>
    <%= fl.text_field "city" %>
  <% end %>
<% end %>

=>
<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="">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 172
def fields_for(name, *yield_args)
  new_base_name = [base_name, name.to_s].compact.join(INPUT_NAME_SEPARATOR)

  builder = self.class.new(
    base_name: new_base_name,
    values: values,
    form_attributes: form_attributes,
    inflector: inflector
  )

  yield(builder, *yield_args)
end
fields_for_collection(name, &block) click to toggle source

Yields to the given block for each element in the matching collection value, and applies the base input name to all fields within the block.

Use this whenever generating form fields for an collection of nested fields.

@param name [String] the input name, also used as the base input name for all fields

within the block

@yieldparam [FormBuilder] the form builder for the nested fields @yieldparam [Integer] the index of the iteration over the collection, starting from zero @yieldparam [Object] the value of the element from the collection

@example Basic usage

<% f.fields_for_collection("addresses") do |fa| %>
  <%= fa.text_field("street") %>
<% end %>

=>
<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="">

@example Yielding index and value

<% f.fields_for_collection("bill.addresses") do |fa, i, address| %>
  <div class="form-group">
    Address id: <%= address.id %>
    <%= fa.label("street") %>
    <%= fa.text_field("street", data: {index: i.to_s}) %>
  </div>
<% end %>

=>
<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" data-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" data-index="1">
</div>

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 228
def fields_for_collection(name, &block)
  _value(name).each_with_index do |value, index|
    fields_for("#{name}.#{index}", index, value, &block)
  end
end
fieldset(...) click to toggle source

@overload fieldset(**attributes, &block)

Returns a fieldset tag.

@param attributes [Hash] the tag's HTML attributes
@yieldreturn [String] the tag's content

@return [String] the tag

@example
  <%= f.fieldset do %>
    <%= f.legend("Author") %>
    <%= f.label("author.name") %>
    <%= f.text_field("author.name") %>
  <% end %>

  # =>
  <fieldset>
    <legend>Author</legend>
    <label for="book-author-name">Name</label>
    <input type="text" name="book[author][name]" id="book-author-name" value="">
  </fieldset>

@since 2.1.0 @api public

# File lib/hanami/helpers/form_helper/form_builder.rb, line 326
def fieldset(...)
  # This is here only for documentation purposes
  tag.fieldset(...)
end
file_field(name, **attributes) click to toggle source

Returns a file input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes @option attributes [String, Array] :accept Optional set of accepted MIME Types @option attributes [Boolean] :multiple allow multiple file upload

@return [String] the tag

@example Basic usage

f.file_field("user.avatar")
=> <input type="file" name="user[avatar]" id="user-avatar">

@example HTML Attributes

f.file_field("user.avatar", class: "avatar-upload")
=> <input type="file" name="user[avatar]" id="user-avatar" class="avatar-upload">

@example Accepted MIME Types

f.file_field("user.resume", accept: "application/pdf,application/ms-word")
=> <input type="file" name="user[resume]" id="user-resume" accept="application/pdf,application/ms-word">

f.file_field("user.resume", accept: ["application/pdf", "application/ms-word"])
=> <input type="file" name="user[resume]" id="user-resume" accept="application/pdf,application/ms-word">

@example Accept multiple file uploads

f.file_field("user.resume", multiple: true)
=> <input type="file" name="user[resume]" id="user-resume" multiple="multiple">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 671
def file_field(name, **attributes)
  form_attributes[:enctype] = "multipart/form-data"

  attributes[:accept] = Array(attributes[:accept]).join(ACCEPT_SEPARATOR) if attributes.key?(:accept)
  attributes = {type: :file, name: _input_name(name), id: _input_id(name), **attributes}

  input(**attributes)
end
hidden_field(name, **attributes) click to toggle source

Returns a hidden input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example

f.hidden_field("delivery.customer_id")
=> <input type="hidden" name="delivery[customer_id]" id="delivery-customer-id" value="">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 637
def hidden_field(name, **attributes)
  input(**_attributes(:hidden, name, attributes))
end
image_button(source, **attributes) click to toggle source

Returns an image input tag, to be used as a visual button for the form.

For security reasons, you should use the absolute URL of the given image.

@param source [String] The absolute URL of the image @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.image_button("https://hanamirb.org/assets/button.png")
=> <input type="image" src="https://hanamirb.org/assets/button.png">

@example HTML Attributes

f.image_button("https://hanamirb.org/assets/button.png", name: "image", width: "50")
=> <input name="image" width="50" type="image" src="https://hanamirb.org/assets/button.png">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1146
def image_button(source, **attributes)
  attributes[:type] = :image
  attributes[:src] = sanitize_url(source)

  input(**attributes)
end
input(...) click to toggle source

Returns an input tag.

Generates an input tag without any special handling. For more convenience and other advanced features, see the other methods of the form builder.

@param attributes [Hash] the tag’s HTML attributes @yieldreturn [String] the tag content

@return [String] the tag

@since 2.1.0 @api public

@example Basic usage

f.input(type: :text, name: "book[title]", id: "book-title", value: book.title)
=> <input type="text" name="book[title]" id="book-title" value="Hanami book">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1219
def input(...)
  tag.input(...)
end
input_text(name, **attributes)
Alias for: text_field
label(content = nil, **attributes, &block) click to toggle source

Returns a label tag.

@return [String] the tag

@overload label(field_name, **attributes)

Returns a label tag for the given field name, with a humanized version of the field name
as the tag's content.

@param field_name [String] the field name
@param attributes [Hash] the tag attributes

@example
  <%= f.label("book.extended_title") %>
  # => <label for="book-extended-title">Extended title</label>

@example HTML attributes
  <%= f.label("book.title", class: "form-label") %>
  # => <label for="book-title" class="form-label">Title</label>

@overload label(content, **attributes)

Returns a label tag for the field name given as `for:`, with the given content string as
the tag's content.

@param content [String] the tag's content
@param for [String] the field name
@param attributes [Hash] the tag attributes

@example
  <%= f.label("Title", for: "book.extended_title") %>
  # => <label for="book-extended-title">Title</label>

  f.label("book.extended_title", for: "ext-title")
  # => <label for="ext-title">Extended title</label>

@overload label(field_name, **attributes, &block)

Returns a label tag for the given field name, with the return value of the given block
as the tag's content.

@param field_name [String] the field name
@param attributes [Hash] the tag attributes
@yieldreturn [String] the tag content

@example
  <%= f.label for: "book.free_shipping" do %>
    Free shipping
    <abbr title="optional" aria-label="optional">*</abbr>
  <% end %>

  # =>
  <label for="book-free-shipping">
    Free shipping
    <abbr title="optional" aria-label="optional">*</abbr>
  </label>

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 290
def label(content = nil, **attributes, &block)
  for_attribute_given = attributes.key?(:for)

  attributes[:for] = _input_id(attributes[:for] || content)

  if content && !for_attribute_given
    content = inflector.humanize(content.to_s.split(INPUT_NAME_SEPARATOR).last)
  end

  tag.label(content, **attributes, &block)
end
month_field(name, **attributes) click to toggle source

Returns a month input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.month_field("book.release_month")
=> <input type="month" name="book[release_month]" id="book-release-month" value="">

@example HTML Attributes

f.month_field("book.release_month", class: "form-control")
=> <input type="month" name="book[release_month]" id="book-release-month" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 534
def month_field(name, **attributes)
  input(**_attributes(:month, name, attributes))
end
number_field(name, **attributes) click to toggle source

Returns a number input tag.

For this tag, you can make use of the ‘max`, `min`, and `step` HTML attributes.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.number_field("book.percent_read")
=> <input type="number" name="book[percent_read]" id="book-percent-read" value="">

@example Advanced attributes

f.number_field("book.percent_read", min: 1, max: 100, step: 1)
=> <input type="number" name="book[percent_read]" id="book-percent-read" value="" min="1" max="100" step="1">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 699
def number_field(name, **attributes)
  input(**_attributes(:number, name, attributes))
end
password_field(name, **attributes) click to toggle source

Returns a password input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.password_field("signup.password")
=> <input type="password" name="signup[password]" id="signup-password" value="">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 861
def password_field(name, **attributes)
  attrs = {type: :password, name: _input_name(name), id: _input_id(name), value: nil, **attributes}
  attrs[:value] = EMPTY_STRING if attrs[:value].nil?

  input(**attrs)
end
radio_button(name, value, **attributes) click to toggle source

Returns a radio input tag.

When editing a resource, the form automatically assigns the ‘checked` HTML attribute for the tag.

@param name [String] the input name @param value [String] the input value @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.radio_button("book.category", "Fiction")
f.radio_button("book.category", "Non-Fiction")

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

@example HTML Attributes

f.radio_button("book.category", "Fiction", class: "form-check")
f.radio_button("book.category", "Non-Fiction", class: "form-check")

=>
<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 request params:
# {book: {category: "Non-Fiction"}}
f.radio_button("book.category", "Fiction")
f.radio_button("book.category", "Non-Fiction")

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

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 841
def radio_button(name, value, **attributes)
  attributes = {type: :radio, name: _input_name(name), value: value, **attributes}
  attributes[:checked] = true if _value(name).to_s == value.to_s

  input(**attributes)
end
range_field(name, **attributes) click to toggle source

Returns a range input tag.

For this tag, you can make use of the ‘max`, `min`, and `step` HTML attributes.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.range_field("book.discount_percentage")
=> <input type="range" name="book[discount_percentage]" id="book-discount-percentage" value="">

@example Advanced attributes

f.range_field("book.discount_percentage", min: 1, max: 1'0, step: 1)
=> <input type="number" name="book[discount_percentage]" id="book-discount-percentage" value="" min="1" max="100" step="1">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 722
def range_field(name, **attributes)
  input(**_attributes(:range, name, attributes))
end
search_field(name, **attributes) click to toggle source

Returns a search input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.search_field("search.q")
=> <input type="search" name="search[q]" id="search-q" value="">

@example HTML Attributes

f.search_field("search.q", class: "form-control")
=> <input type="search" name="search[q]" id="search-q" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 798
def search_field(name, **attributes)
  input(**_attributes(:search, name, attributes))
end
select(name, values, **attributes) click to toggle source

Returns a select input tag containing option tags for the given values.

The values should be an enumerable of pairs of content (the displayed text for the option) and value (the value for the option) strings.

When editing a resource, automatically assigns the ‘selected` HTML attribute for any option tags matching the resource’s values.

@param name [String] the input name @param values [Hash] a Hash to generate ‘<option>` tags. @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

values = {"Italy" => "it", "Australia" => "au"}
f.select("book.store", values)

=>
<select name="book[store]" id="book-store">
  <option value="it">Italy</option>
  <option value="au">Australia</option>
</select>

@example HTML Attributes

values = {"Italy" => "it", "Australia" => "au"}
f.select("book.store", values, class: "form-control")

=>
<select name="book[store]" id="book-store" class="form-control">
  <option value="it">Italy</option>
  <option value="au">Australia</option>
</select>

@example Selected options

# Given the following request params:
# {book: {store: "it"}}
values = {"Italy" => "it", "Australia" => "au"}
f.select("book.store", values)

=>
<select name="book[store]" id="book-store">
  <option value="it" selected="selected">Italy</option>
  <option value="au">Australia</option>
</select>

@example Prompt option

values = {"Italy" => "it", "Australia" => "au"}
f.select("book.store", values, options: {prompt: "Select a store"})

=>
<select name="book[store]" id="book-store">
  <option>Select a store</option>
  <option value="it">Italy</option>
  <option value="au">Australia</option>
</select>

@example Selected option

values = {"Italy" => "it", "Australia" => "au"}
f.select("book.store", values, options: {selected: "it"})

=>
<select name="book[store]" id="book-store">
  <option value="it" selected="selected">Italy</option>
  <option value="au">Australia</option>
</select>

@example Prompt option and HTML attributes

values = {"Italy" => "it", "Australia" => "au"}
f.select("book.store", values, options: {prompt: "Select a store"}, class: "form-control")

=>
<select name="book[store]" id="book-store" class="form-control">
  <option>Select a store</option>
  <option value="it">Italy</option>
  <option value="au">Australia</option>
</select>

@example Multiple select

values = {"Italy" => "it", "Australia" => "au"}
f.select("book.stores", values, multiple: true)

=>
<select name="book[store][]" id="book-store" multiple="multiple">
 <option value="it">Italy</option>
  <option value="au">Australia</option>
</select>

@example Multiple select and HTML attributes

values = {"Italy" => "it", "Australia" => "au"}
f.select("book.stores", values, multiple: true, class: "form-control")

=>
<select name="book[store][]" id="book-store" multiple="multiple" class="form-control">
  <option value="it">Italy</option>
  <option value="au">Australia</option>
</select>

@example Values as an array, supporting repeated entries

values = [["Italy", "it"],
          ["---", ""],
          ["Afghanistan", "af"],
          ...
          ["Italy", "it"],
          ...
          ["Zimbabwe", "zw"]]
f.select("book.stores", values)

=>
<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>

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 989
def select(name, values, **attributes) # rubocop:disable Metrics/AbcSize
  options = attributes.delete(:options) { {} }
  multiple = attributes[:multiple]
  attributes = {name: _select_input_name(name, multiple), id: _input_id(name), **attributes}
  prompt = options.delete(:prompt)
  selected = options.delete(:selected)
  input_value = _value(name)

  option_tags = []
  option_tags << tag.option(prompt) 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_tags << tag.option(content, value: value, selected: true, **options)
    else
      option_tags << tag.option(content, value: value, **options)
    end
  end

  tag.select(option_tags.join.html_safe, **attributes)
end
submit(content = nil, **attributes, &blk) click to toggle source

Returns a submit button tag.

@return [String] the tag

@overload submit(content, **attributes)

Returns a submit button tag with the given content.

@param content [String] the content for the tag
@param attributes [Hash] the tag's HTML attributes

@overload submit(**attributes, &blk)

Returns a submit button tag with the return value of the given block as the tag's
content.

@param attributes [Hash] the tag's HTML attributes
@yieldreturn [String] the tag content

@example Basic usage

f.submit("Create")
=> <button type="submit">Create</button>

@example HTML Attributes

f.submit("Create", class: "btn btn-primary")
=> <button type="submit" class="btn btn-primary">Create</button>

@example Returning content from a block

<%= f.submit(class: "btn btn-primary") do %>
  <span class="oi oi-check">
<% end %>

=>
<button type="submit" class="btn btn-primary">
  <span class="oi oi-check"></span>
</button>

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1190
def submit(content = nil, **attributes, &blk)
  if content.is_a?(::Hash)
    attributes = content
    content = nil
  end

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

Returns a telephone input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example

f.tel_field("user.telephone")
=> <input type="tel" name="user[telephone]" id="user-telephone" value="">

@example HTML Attributes

f.tel_field("user.telephone", class: "form-control")
=> <input type="tel" name="user[telephone]" id="user-telephone" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 620
def tel_field(name, **attributes)
  input(**_attributes(:tel, name, attributes))
end
text_area(name, content = nil, **attributes) click to toggle source

Returns a textarea tag.

@param name [String] the input name @param content [String] the content of the textarea @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.text_area("user.hobby")
=> <textarea name="user[hobby]" id="user-hobby"></textarea>

f.text_area "user.hobby", "Football"
=>
<textarea name="user[hobby]" id="user-hobby">
Football</textarea>

@example HTML attributes

f.text_area "user.hobby", class: "form-control"
=> <textarea name="user[hobby]" id="user-hobby" class="form-control"></textarea>

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 749
def text_area(name, content = nil, **attributes)
  if content.respond_to?(:to_hash)
    attributes = content
    content = nil
  end

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

Returns a text input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.text_field("user.first_name")
=> <input type="text" name="user[first_name]" id="user-first-name" value="">

@example HTML Attributes

f.text_field("user.first_name", class: "form-control")
=> <input type="text" name="user[first_name]" id="user-first-name" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 776
def text_field(name, **attributes)
  input(**_attributes(:text, name, attributes))
end
Also aliased as: input_text
time_field(name, **attributes) click to toggle source

Returns a time input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.time_field("book.release_hour")
=> <input type="time" name="book[release_hour]" id="book-release-hour" value="">

@example HTML Attributes

f.time_field("book.release_hour", class: "form-control")
=> <input type="time" name="book[release_hour]" id="book-release-hour" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 513
def time_field(name, **attributes)
  input(**_attributes(:time, name, attributes))
end
url_field(name, **attributes) click to toggle source

Returns a URL input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.url_field("user.website")
=> <input type="url" name="user[website]" id="user-website" value="">

@example HTML Attributes

f.url_field("user.website", class: "form-control")
=> <input type="url" name="user[website]" id="user-website" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 597
def url_field(name, **attributes)
  attributes[:value] = sanitize_url(attributes.fetch(:value) { _value(name) })

  input(**_attributes(:url, name, attributes))
end
week_field(name, **attributes) click to toggle source

Returns a week input tag.

@param name [String] the input name @param attributes [Hash] the tag’s HTML attributes

@return [String] the tag

@example Basic usage

f.week_field("book.release_week")
=> <input type="week" name="book[release_week]" id="book-release-week" value="">

@example HTML Attributes

f.week_field("book.release_week", class: "form-control")
=> <input type="week" name="book[release_week]" id="book-release-week" value="" class="form-control">

@api public @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 555
def week_field(name, **attributes)
  input(**_attributes(:week, name, attributes))
end

Private Instance Methods

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

@api private @since 2.1.0

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

@api private @since 2.1.0

@see check_box

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

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

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

@api private @since 1.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1381
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
_csrf_token(values, attributes) click to toggle source

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1242
def _csrf_token(values, attributes)
  return [] if values.csrf_token.nil?

  return [] if EXCLUDED_CSRF_METHODS.include?(attributes[:method])

  [true, values.csrf_token]
end
_form_method(attributes) click to toggle source

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1227
def _form_method(attributes)
  attributes[:method] ||= DEFAULT_METHOD
  attributes[:method] = attributes[:method].to_s.upcase

  original_form_method = attributes[:method]

  if (method_override = !BROWSER_METHODS.include?(attributes[:method]))
    attributes[:method] = DEFAULT_METHOD
  end

  [method_override, original_form_method]
end
_hidden_field_for_check_box(name, attributes) click to toggle source

@api private @since 2.1.0

@see check_box

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

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

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1283
def _input_id(name)
  [base_name, name].compact.join(INPUT_NAME_SEPARATOR).to_s.tr("._", "-")
end
_input_name(name) click to toggle source

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1266
def _input_name(name)
  tokens = _split_input_name(name)
  result = tokens.shift

  tokens.each do |t|
    if t =~ %r{\A\d+\z}
      result << "[]"
    else
      result << "[#{t}]"
    end
  end

  result
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 1357
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 1373
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 1365
def _is_in_selected_values?(multiple, selected, value)
  return unless multiple && selected.is_a?(Array)

  selected.include?(value)
end
_select_input_name(name, multiple) click to toggle source

@api private @since 1.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1336
def _select_input_name(name, multiple)
  select_name = _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 @since 1.2.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1344
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_current_value?(input_value, value) ||
      _is_in_selected_values?(multiple, selected, value) ||
      _is_in_input_values?(multiple, input_value, value)
  end
end
_split_input_name(name) click to toggle source

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1295
def _split_input_name(name)
  [
    *base_name.to_s.split(INPUT_NAME_SEPARATOR),
    *name.to_s.split(INPUT_NAME_SEPARATOR)
  ].compact
end
_value(name) click to toggle source

@api private @since 2.1.0

# File lib/hanami/helpers/form_helper/form_builder.rb, line 1289
def _value(name)
  values.get(*_split_input_name(name).map(&:to_sym))
end