Module: Hanami::Helpers::FormHelper

Includes:
HtmlHelper
Defined in:
gems/gems/hanami-helpers-1.3.0/lib/hanami/helpers/form_helper.rb,
gems/gems/hanami-helpers-1.3.0/lib/hanami/helpers/form_helper/values.rb,
gems/gems/hanami-helpers-1.3.0/lib/hanami/helpers/form_helper/html_node.rb,
gems/gems/hanami-helpers-1.3.0/lib/hanami/helpers/form_helper/form_builder.rb

Overview

Form builder

By including Hanami::Helpers::FormHelper it will inject one public method: form_for. This is a HTML5 form builder.

To understand the general HTML5 builder syntax of this framework, please consider to have a look at Hanami::Helpers::HtmlHelper documentation.

This builder is independent from any template engine. This was hard to achieve without a compromise: the form helper should be used in one output block in a template or as a method in a view (see the examples below).

Features:

  • Support for complex markup without the need of concatenation

  • Auto closing HTML5 tags

  • Support for view local variables

  • Method override support (PUT/PATCH/DELETE HTTP verbs aren't understood by browsers)

  • Automatic generation of HTML attributes for inputs: id, name, value

  • Allow to override HTML attributes

  • Extract values from request params and fill value attributes

  • Automatic selection of current value for radio button and select inputs

  • Infinite nested fields

Supported tags and inputs:

  • check_box

  • color_field

  • date_field

  • datetime_field

  • datetime_local_field

  • email_field

  • fields_for

  • file_field

  • form_for

  • hidden_field

  • label

  • number_field

  • password_field

  • radio_button

  • select

  • submit

  • text_area

  • text_field

Examples:

One output block (template)

<%=
  form_for :book, routes.books_path do
    text_field :title

    submit 'Create'
  end
%>

Method (view)

require 'hanami/helpers'

class MyView
  include Hanami::Helpers::FormHelper

  def my_form
    form_for :book, routes.books_path do
      text_field :title
    end
  end
end

<!-- use this in the template -->
<%= my_form %>

See Also:

Since:

  • 0.2.0

Defined Under Namespace

Classes: Form, FormBuilder

Instance Method Summary collapse

Methods included from HtmlHelper

#html

Instance Method Details

#csrf_meta_tagsHanami::Helpers::HtmlHelper::HtmlBuilder, NilClass

Prints CSRF meta tags for Unobtrusive JavaScript (UJS) purposes.

Examples:

<html>
  <head>
    <!-- ... -->
    <%= csrf_meta_tags %>
  </head>
  <!-- ... -->
</html>

<html>
  <head>
    <!-- ... -->
    <meta name="csrf-param" content="_csrf_token">
    <meta name="csrf-token" content="4a038be85b7603c406dcbfad4b9cdf91ec6ca138ed6441163a07bb0fdfbe25b5">
  </head>
  <!-- ... -->
</html>

Returns:

Since:

  • 1.2.0

def csrf_meta_tags
  return if csrf_token.nil?

  html.meta(name: "csrf-param", content: CSRF_TOKEN) +
    html.meta(name: "csrf-token", content: csrf_token)
end

#csrf_tokenString, NilClass

Returns CSRF Protection Token stored in session.

It returns nil if sessions aren't enabled or the value is missing.

Returns:

  • (String, NilClass)

    token, if present

Since:

  • 0.2.0

def csrf_token
  if defined?(session)
    session[CSRF_TOKEN]
  elsif defined?(locals) && locals[:session]
    locals[:session][CSRF_TOKEN]
  end
end

#form_for(name, url, options, &blk) ⇒ Hanami::Helpers::FormHelper::FormBuilder #form_for(form, attributes = {}, &blk) ⇒ Hanami::Helpers::FormHelper::FormBuilder

Instantiate a HTML5 form builder

Examples:

Inline Values In Template

<%=
  form_for :book, routes.books_path, class: 'form-horizontal' do
    div do
      label      :title
      text_field :title, class: 'form-control'
    end

    submit 'Create'
  end
%>

<!-- output -->

<form action="/books" method="POST" accept-charset="utf-8" id="book-form" class="form-horizontal">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <div>
    <label for="book-title">Title</label>
    <input type="text" name="book[title]" id="book-title" value="Test Driven Development">
  </div>

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

Use In A View


module Web::Views::Books
  class New

  def form
    form_for :book, routes.books_path, class: 'form-horizontal' do
      div do
        label      :title
        text_field :title, class: 'form-control'
      end

      submit 'Create'
    end
  end
end

<!-- in the corresponding template use this -->
<%= form %>

<!-- output -->

<form action="/books" method="POST" accept-charset="utf-8" id="book-form" class="form-horizontal">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <div>
    <label for="book-title">Title</label>
    <input type="text" name="book[title]" id="book-title" value="Test Driven Development">
  </div>

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

Share Code Between Views


# Given the following views to create and update a resource
module Web::Views::Books
  class New
    include Web::View

    def form
      Form.new(:book, routes.books_path)
    end

    def submit_label
      'Create'
    end
  end

  class Edit
    include Web::View

    def form
      Form.new(:book, routes.book_path(id: book.id),
        {book: book}, {method: :patch})
    end

    def submit_label
      'Update'
    end
  end
end

# The respective templates can be identical:

## books/new.html.erb
<%= render partial: 'books/form' %>

## books/edit.html.erb
<%= render partial: 'books/form' %>

# While the partial can have the following markup:

## books/_form.html.erb
<%=
  form_for form, class: 'form-horizontal' do
    div do
      label      :title
      text_field :title, class: 'form-control'
    end

    submit submit_label
  end
%>

<!-- output -->

<form action="/books" method="POST" accept-charset="utf-8" id="book-form" class="form-horizontal">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <div>
    <label for="book-title">Title</label>
    <input type="text" name="book[title]" id="book-title" value="Test Driven Development">
  </div>

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

Method override

<%=
  form_for :book, routes.book_path(id: book.id), method: :put do
    text_field :title

    submit 'Update'
  end
%>

<!-- output -->

<form action="/books/23" accept-charset="utf-8" id="book-form" method="POST">
  <input type="hidden" name="_method" value="PUT">
  <input type="hidden" name="_csrf_token" value="920cd5bfaecc6e58368950e790f2f7b4e5561eeeab230aa1b7de1b1f40ea7d5d">
  <input type="text" name="book[title]" id="book-title" value="Test Driven Development">

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

Nested fields

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

    fields_for :address do
      text_field :city
    end

    submit 'Create'
  end
%>

<!-- output -->

<form action="/deliveries" accept-charset="utf-8" id="delivery-form" method="POST">
  <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][city]" id="delivery-address-city" value="">

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

Overloads:

  • #form_for(name, url, options, &blk) ⇒ Hanami::Helpers::FormHelper::FormBuilder

    Use inline values

    Parameters:

    • name (Symbol)

      the toplevel name of the form, it's used to generate input names, ids, and to lookup params to fill values.

    • url (String)

      the form action URL

    • options (Hash)

      HTML attributes to pass to the form tag and form values

    • blk (Proc)

      A block that describes the contents of the form

    Options Hash (options):

    • :values (Hash)

      An optional payload of objects to pass

  • #form_for(form, attributes = {}, &blk) ⇒ Hanami::Helpers::FormHelper::FormBuilder

    Use Form

    Parameters:

    • form (Hanami::Helpers::FormHelper::Form)

      a form object

    • attributes (Hash) (defaults to: {})

      HTML attributes to pass to the form tag and form values

    • blk (Proc)

      A block that describes the contents of the form

Returns:

See Also:

Since:

  • 0.2.0

def form_for(name, url = nil, options = {}, &blk)
  form = if name.is_a?(Form)
           options = url || {}
           name
         else
           Form.new(name, url, options.delete(:values))
         end

  opts = options.dup
  opts[:data-remote"] = opts.delete(:remote) if opts.key?(:remote)
  attributes = { action: form.url, method: form.verb, 'accept-charset': DEFAULT_CHARSET, id: "#{form.name}-form" }.merge(opts)

  FormBuilder.new(form, attributes, self, &blk)
end