module ActionView::Helpers::FormHelper

def apply_form_for_options!(record, object, options) #:nodoc:

:nodoc:
def apply_form_for_options!(record, object, options) #:nodoc:
  object = convert_to_model(object)
  as = options[:as]
  namespace = options[:namespace]
  action, method = object.respond_to?(:persisted?) && object.persisted? ? [:edit, :patch] : [:new, :post]
  options[:html].reverse_merge!(
    class:  as ? "#{action}_#{as}" : dom_class(object, action),
    id:     (as ? [namespace, action, as] : [namespace, dom_id(object, action)]).compact.join("_").presence,
    method: method
  )
  options[:url] ||= if options.key?(:format)
    polymorphic_path(record, format: options.delete(:format))
  else
    polymorphic_path(record, {})
  end
end

def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")

#
# =>
check_box("eula", "accepted", { class: 'eula_check' }, "yes", "no")

#
# =>
check_box("puppy", "gooddog", {}, "yes", "no")
# Let's say that @puppy.gooddog is "no":

#
# =>
check_box("post", "validated")
# Let's say that @post.validated? is 1:

hashes instead of arrays.
In that case it is preferable to either use +check_box_tag+ or to use

get an extra ghost item with only that attribute, assigned to "0".
the elements of the array. For each item with a checked check box you
because parameter name repetition is precisely what Rails seeks to distinguish

<% end %>
...
<%= form.check_box :paid %>
<%= fields_for "project[invoice_attributes][]", invoice, index: nil do |form| %>

within an array-like parameter, as in
Unfortunately that workaround does not work when the check box goes

key in the query string, that works for ordinary forms.
form, and parameters extraction gets the last occurrence of any repeated
says key/value pairs have to be sent in the same order they appear in the
the check box is unchecked), or both fields. Since the HTML specification
This way, the client either sends only the hidden field (representing

attributes mimic an unchecked check box.
the very check box. The hidden field has the same name and its
To prevent this the helper generates an auxiliary hidden field before

wouldn't update the flag.

@invoice.update(params[:invoice])

any mass-assignment idiom like
invoice the user unchecks its check box, no +paid+ parameter is sent. So,
if an +Invoice+ model has a +paid+ flag, and in the form that edits a paid
thus web browsers do not send them. Unfortunately this introduces a gotcha:
The HTML specification says unchecked check boxes are not successful, and

==== Gotcha

while the default +unchecked_value+ is set to 0 which is convenient for boolean values.
Additional options on the input tag can be passed as a hash with +options+. The +checked_value+ defaults to 1
It's intended that +method+ returns an integer and if that integer is above zero, then the checkbox is checked.
assigned to the template (identified by +object+). This object must be an instance object (@object) and not a local object.
Returns a checkbox tag tailored for accessing a specified attribute (identified by +method+) on an object
def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
  Tags::CheckBox.new(object_name, method, self, checked_value, unchecked_value, options).render
end

def color_field(object_name, method, options = {})

# =>
color_field("car", "color")

Returns a text_field of type "color".
def color_field(object_name, method, options = {})
  Tags::ColorField.new(object_name, method, self, options).render
end

def date_field(object_name, method, options = {})


# =>
date_field("user", "born_on", min: "2014-05-20")

values for "min" and "max."
Alternatively, you can pass a String formatted as an ISO8601 date as the

# =>
date_field("user", "born_on", min: Date.today)

instances of Date or Time to the options hash.
You can create values for the "min" and "max" attributes by passing

# =>
date_field("user", "born_on", value: "1984-05-12")
@user.born_on = Date.new(1984, 1, 27)

by passing the "value" option explicitly, e.g.
of DateTime and ActiveSupport::TimeWithZone. You can still override that
on the object's value, which makes it behave as expected for instances
The default value is generated by trying to call +strftime+ with "%Y-%m-%d"

# =>
date_field("user", "born_on")

Returns a text_field of type "date".
def date_field(object_name, method, options = {})
  Tags::DateField.new(object_name, method, self, options).render
end

def datetime_field(object_name, method, options = {})


# =>
datetime_field("user", "born_on", min: "2014-05-20T00:00:00")

the values for "min" and "max."
Alternatively, you can pass a String formatted as an ISO8601 datetime as

# =>
datetime_field("user", "born_on", min: Date.today)

instances of Date or Time to the options hash.
You can create values for the "min" and "max" attributes by passing

# =>
datetime_field("user", "born_on")
@user.born_on = Date.new(1984, 1, 12)

of DateTime and ActiveSupport::TimeWithZone.
on the object's value, which makes it behave as expected for instances
The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T"

# =>
datetime_field("user", "born_on")

Returns a text_field of type "datetime-local".
def datetime_field(object_name, method, options = {})
  Tags::DatetimeLocalField.new(object_name, method, self, options).render
end

def default_form_builder_class

def default_form_builder_class
  builder = default_form_builder || ActionView::Base.default_form_builder
  builder.respond_to?(:constantize) ? builder.constantize : builder
end

def email_field(object_name, method, options = {})


# =>
email_field("user", "address")

Returns a text_field of type "email".
def email_field(object_name, method, options = {})
  Tags::EmailField.new(object_name, method, self, options).render
end

def fields(scope = nil, model: nil, **options, &block)

FormOptionsHelper#collection_select and DateHelper#datetime_select.
to work with an object as a base, like
Same goes for the methods in FormOptionsHelper and DateHelper designed

<% end %>
<%= check_box_tag "comment[all_caps]", "1", @comment.commenter.hulk_mode? %>
<%= text_area :commenter, :biography %>

<%= fields.text_field :body %>
<%= fields model: @comment do |fields| %>

from FormTagHelper:
match the stand-alone FormHelper methods and methods
While +form_with+ uses a FormBuilder object it's possible to mix and

=== Mixing with other form helpers

either the passed scope or the scope inferred from the :model.
or model is yielded, so any generated field names are prefixed with
Much like +form_with+ a FormBuilder instance associated with the scope

<% end %>
<% end %>
<%= fields.text_field :body %>
<%= form.fields :comment do |fields| %>

<%= form.text_field :title %>
<%= form_with model: @post do |form| %>
# Using +fields+ with +form_with+:

# =>
<% end %>
<%= fields.text_field :body %>
<%= fields model: Comment.new(body: "full bodied") do |fields| %>
# Using a model infers the scope and assigns field values:

# =>
<% end %>
<%= fields.text_field :body %>
<%= fields :comment do |fields| %>
# Using a scope prefixes the input field names:

except it doesn't output the form tags.
Like +form_with+ does with :scope or :model,
Scopes input fields with either an explicit scope or model.
def fields(scope = nil, model: nil, **options, &block)
  options[:allow_method_names_outside_object] = true
  options[:skip_default_ids] = !form_with_generates_ids
  if model
    scope ||= model_name_from_record_or_class(model).param_key
  end
  builder = instantiate_builder(scope, model, options)
  capture(builder, &block)
end

def fields_for(record_name, record_object = nil, options = {}, &block)

to prevent fields_for from rendering it automatically.
hidden field is not needed and you can pass include_id: false
to store the ID of the record. There are circumstances where this
Note that fields_for will automatically generate a hidden field

<% end %>
...
<% end %>
...
Project #<%= project_fields.index %>
<%= person_form.fields_for :projects do |project_fields| %>
...
<%= form_for @person do |person_form| %>

is available in the FormBuilder object.
object into the array. For this purpose, the index method
When a collection is used you might want to know the index of each

<% end %>
...
<% end %>
Delete: <%= project_fields.check_box :_destroy %>
<%= person_form.fields_for :projects do |project_fields| %>
...
<%= form_for @person do |person_form| %>

(eg. 1, '1', true, or 'true'):
parameter with a value that evaluates to +true+
attributes hash by adding a form element for the _destroy
This will allow you to specify which models to destroy in the

end
accepts_nested_attributes_for :projects, allow_destroy: true
has_many :projects
class Person < ActiveRecord::Base

option for +accepts_nested_attributes_for+:
form, you have to enable it first using the :allow_destroy
If you want to destroy any of the associated models through the

<% end %>
...
<% end %>
Name: <%= project_fields.text_field :name %>
<%= person_form.fields_for :projects, @active_projects do |project_fields| %>
...
<%= form_for @person do |person_form| %>

Or a collection to be used:

<% end %>
...
<% end %>
<% end %>
<% end %>
Name: <%= project_fields.text_field :name %>
<%= person_form.fields_for :projects, project do |project_fields| %>
<% if project.active? %>
<% @person.projects.each do |project| %>
...
<%= form_for @person do |person_form| %>

It's also possible to specify the instance to be used:

<% end %>
...
<% end %>
<% end %>
Name: <%= project_fields.text_field :name %>
<% if project_fields.object.active? %>
<%= person_form.fields_for :projects do |project_fields| %>
...
<%= form_for @person do |person_form| %>

collection:
the nested fields_for call will be repeated for each instance in the
This model can now be used with a nested fields_for. The block given to

end
accepts_nested_attributes_for :projects
has_many :projects
class Person < ActiveRecord::Base

+accepts_nested_attributes_for+ to define the writer method for you:
When projects is already an association on Person you can use

collection, and the correct indices to be set in the form markup.
required for fields_for to correctly identify :projects as a
Note that the projects_attributes= writer method is in fact

end
end
# Process the attributes hash
def projects_attributes=(attributes)

end
[@project1, @project2]
def projects
class Person

projects_attributes= writer method:
from the projects reader method and responds to the
Consider a Person class which returns an _array_ of Project instances

==== One-to-many

<% end %>
...
<% end %>
Delete: <%= address_fields.check_box :_destroy %>
...
<%= person_form.fields_for :address do |address_fields| %>
...
<%= form_for @person do |person_form| %>

model (eg. 1, '1', true, or 'true'):
with a value that evaluates to +true+, you will destroy the associated
Now, when you use a form element with the _destroy parameter,

end
accepts_nested_attributes_for :address, allow_destroy: true
has_one :address
class Person < ActiveRecord::Base

+accepts_nested_attributes_for+:
to enable it first using the :allow_destroy option for
If you want to destroy the associated model through the form, you have

end
accepts_nested_attributes_for :address
has_one :address
class Person < ActiveRecord::Base

+accepts_nested_attributes_for+ to define the writer method for you:
When address is already an association on a Person you can use

<% end %>
...
<% end %>
Zip code: <%= address_fields.text_field :zip_code %>
Street : <%= address_fields.text_field :street %>
<%= person_form.fields_for :address do |address_fields| %>
...
<%= form_for @person do |person_form| %>

This model can now be used with a nested fields_for, like so:

end
end
# Process the attributes hash
def address_attributes=(attributes)

end
@address
def address
class Person

address_attributes= writer method:
address reader method and responds to the
Consider a Person class which returns a _single_ Address from the

==== One-to-one

or an _array_ of objects.
depends on whether the normal reader method returns a _single_ object
Whether a one-to-one or one-to-many style form builder will be yielded

address_attributes=.
writer for the association :address is called
defining a method with the proper name. For example: the attribute
with +accepts_nested_attributes_for+ in a model definition or by
association. The most common way of defining these writers is either
Nested attribute writers are normal setter methods named after an

the attributes of a parent object and its associations in one go.
for that attribute. This allows you to create forms that set or change
writer for a certain attribute, fields_for will yield a new scope
When the object belonging to the current scope has a nested attribute

=== Nested Attributes Examples

FormOptionsHelper#collection_select and DateHelper#datetime_select.
DateHelper that are designed to work with an object as base, like
Note: This also works for the methods in FormOptionsHelper and

of class +Permission+, the field will still be named permission[admin].
_class_ of the model object, e.g. if @person.permission, is
and +fields_for+ will derive the required name of the field from the

<% end %>
Admin?: <%= permission_fields.check_box :admin %>
<%= fields_for @person.permission do |permission_fields| %>

name has been omitted) -
argument isn't a string or symbol +fields_for+ will realize that the
Alternatively, you can pass just the model object itself (if the first

field will reflect the value of that variable's attribute @permission.admin.
instance variable @permission, the initial state of the input
...in which case, if :permission also happens to be the name of an

<% end %>
Admin?: <%= permission_fields.check_box :admin %>
<%= fields_for :permission do |permission_fields| %>

object to +fields_for+ -
Often this can be simplified by passing just the name of the model

reflect the value of @person.permission.admin.
+admin+, the initial state of the checkbox when first displayed will
If @person.permission is an existing record with an attribute
value will appear in the controller as params[:permission][:admin].
tag with the +name+ attribute permission[admin], and the submitted
In this case, the checkbox field will be represented by an HTML +input+

<% end %>
<%= person_form.submit %>

<% end %>
Admin? : <%= permission_fields.check_box :admin %>
<%= fields_for :permission, @person.permission do |permission_fields| %>

Last name : <%= person_form.text_field :last_name %>
First name: <%= person_form.text_field :first_name %>
<%= form_for @person do |person_form| %>

object itself can be passed to the method separately -
both an object name (represented by either a symbol or string) and the
displayed. In order for both of these features to be specified independently,
default values are shown when the form the fields appear in is first
values appear within the +params+ hash in the controller) and what
a model object in two ways - how they are named (hence how submitted
generate fields associated with the model object. Fields may reflect
and within the block allows methods to be called on the builder to
a FormBuilder object associated with a particular model object to a block,
its method signature is slightly different. Like +form_for+, it yields
Although the usage and purpose of +fields_for+ is similar to +form_for+'s,

for specifying additional model objects in the same form.
doesn't create the form tags themselves. This makes fields_for suitable
Creates a scope around a specific model object like form_for, but
def fields_for(record_name, record_object = nil, options = {}, &block)
  builder = instantiate_builder(record_name, record_object, options)
  capture(builder, &block)
end

def file_field(object_name, method, options = {})

# =>
file_field(:attachment, :file, class: 'file_input')

# =>
file_field(:post, :image, accept: 'image/png,image/gif,image/jpeg')

# =>
file_field(:post, :attached, accept: 'text/html')

# =>
file_field(:post, :image, multiple: true)

# =>
file_field(:user, :avatar)
==== Examples

* :accept - If set to one or multiple mime-types, the user will be suggested a filter when choosing a file. You still need to set up model validations.
* :multiple - If set to true, *in most updated browsers* the user will be allowed to select multiple files.
* :disabled - If set to true, the user will not be able to use this input.
* Creates standard HTML attributes for the tag.
==== Options

Using this method inside a +form_for+ block will set the enclosing form's encoding to multipart/form-data.

shown.
hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
assigned to the template (identified by +object+). Additional options on the input tag can be passed as a
Returns a file upload input tag tailored for accessing a specified attribute (identified by +method+) on an object
def file_field(object_name, method, options = {})
  Tags::FileField.new(object_name, method, self, convert_direct_upload_option_to_url(options.dup)).render
end

def form_for(record, options = {}, &block)

<% end %>
...
<%= form_for @invoice, url: external_url, authenticity_token: false do |f| %>

If you don't want to an authenticity token field be rendered at all just pass false:

<% end %>
...
<%= form_for @invoice, url: external_url, authenticity_token: 'external_token' do |f| %>

To set an authenticity token you need to pass an :authenticity_token parameter

without it, for example when you submit data to a payment gateway number and types of fields could be limited.
When you build forms to external resources sometimes you need to set an authenticity token or just render a form

=== Form to external resources

FormTagHelper#form_tag.
If you don't need to attach a form to a model instance, then check out

end
form_for(record_or_name_or_array, *(args << options.merge(builder: LabellingFormBuilder)), &block)
options = args.extract_options!
def labelled_form_for(record_or_name_or_array, *args, &block)

could do something like the following:
In many cases you will want to wrap the above in another helper, so you

of a nested fields_for call, unless it's explicitly set.
The custom FormBuilder class is automatically merged with the options

labelling_form.
variable referencing the form builder is called
The rendered template is people/_labelling_form and the local

<%= render f %>

In this case, if you use this:

<% end %>
<%= f.submit %>
<%= f.check_box :admin %>
<%= f.text_area :biography %>
<%= f.text_field :last_name %>
<%= f.text_field :first_name %>
<%= form_for @person, url: { action: "create" }, builder: LabellingFormBuilder do |f| %>

automatically add labels to form inputs.
custom builder. For example, let's say you made a helper to
FormBuilder and override or define some more helpers, then use your
You can also build forms using a customized FormBuilder class. Subclass

=== Customized form builders

<% end %>
<% end %>
...
<%= f.fields_for(:comments, include_id: false) do |cf| %>
<%= form_for(@post) do |f| %>

Example:

thus there is no primary key for comments.
In the following example the Post model has many Comments stored within it in a NoSQL database,

to disable the hidden id.
Some ORM systems do not use IDs on nested models so in this case you want to be able
This is used to maintain the correlation between the form data and its associated model.
The form_for method automatically includes the model id as a hidden field in the form.

=== Removing hidden model id's


...



The HTML generated for this would be:

<% end %>
...
<%= form_for(@post, data: { behavior: "autosave" }, html: { name: "go" }) do |f| %>

the HTML key. Example:
You can set data attributes directly by passing in a data hash, but all other HTML options must be wrapped in

=== Setting HTML options


...



The HTML generated for this would be:

<% end %>
...
<%= form_for(@post, remote: true) do |f| %>

Example:

a regular submission as viewed by the receiving side (all elements available in params).
Even though it's using JavaScript to serialize the form elements, the form submission will work just like
POST arrangement, but ultimately the behavior is the choice of the JavaScript driver implementor.
behavior. The expected default behavior is an XMLHttpRequest in the background instead of the regular
in the options hash creates a form that will allow the unobtrusive JavaScript drivers to modify its

remote: true

Specifying:

=== Unobtrusive JavaScript

called _method will carry the intended verb for the server to interpret.
supported by HTML forms, the form will be set to POST and a hidden input
in the options hash. If the verb is not GET or POST, which are natively

method: (:get|:post|:patch|:put|:delete)

You can force the form to use the full array of HTTP verbs by setting

=== Setting the method

@comment = Comment.new.
Where @document = Document.find(params[:id]) and

<% end %>
...
<%= form_for([@document, @comment]) do |f| %>

to the document given that the routes are set correctly:
If your resource has associations defined, for example, you want to add comments

<% end %>
...
<%= form_for([:admin, @post]) do |f| %>

For namespaced routes, like +admin_post_url+:

<% end %>
...
<%= form_for(@post, format: :json) do |f| %>

You can also set the answer format, like this:

<% end %>
...
<%= form_for(@post, url: super_posts_path) do |f| %>

However you can still overwrite individual conventions, such as:

<% end %>
...
<%= form_for @post, as: :post, url: posts_path, html: { class: "new_post", id: "new_post" } do |f| %>

is equivalent to something like:

<% end %>
...
<%= form_for(Post.new) do |f| %>

And for a new record

<% end %>
...
<%= form_for @post, as: :post, url: post_path(@post), method: :patch, html: { class: "edit_post", id: "edit_post_45" } do |f| %>

is then equivalent to something like:

<% end %>
...
<%= form_for @post do |f| %>

appropriate URL from the record itself. For example,
in config/routes.rb. In this case Rails will simply infer the
to a set of RESTful routes, e.g. defined using the +resources+ method
if the record passed to +form_for+ is a _resource_, i.e. it corresponds
form is going to be sent. However, further simplification is possible
need to use the :url option in order to specify where the
In the examples just shown, although not indicated explicitly, we still

=== Resource-oriented style

values of the attributes of +post+.
would produce a form with fields whose initial state reflect the current

<% end %>
...
<%= form_for post do |f| %>

representing an existing record,
variable. So, for example, if we had a _local_ variable +post+
regardless of whether the object is an instance
are taken from the attributes of the object passed to +form_for+,
Secondly, the field values shown when the form is initially displayed

would result in params[:client].

<% end %>
...
<%= form_for(@person, as: :client) do |f| %>

the :as option, e.g. -
if the object's class is +Post+. However, this can be overwritten using
hash) is actually derived from the object's _class_, e.g. params[:post]
elements within the form (hence the key that denotes them in the +params+
couple of small exceptions. First, the prefix used to name the input
This behaves in almost the same way as outlined previously, with a

<% end %>
...
<%= form_for @post do |f| %>

is an existing record you wish to edit, you can create the form using
to pass a model object itself to +form_for+. For example, if @post
a string can also be used equivalently. It is also possible, however,
represented by a symbol passed to +form_for+, and we noted that
In the examples above, the object to be created or edited was

=== #form_for with a model object

FormOptionsHelper#collection_select and DateHelper#datetime_select.
are designed to work with an object as base, like
This also works for the methods in FormOptionsHelper and DateHelper that

<% end %>
<%= f.submit %>
Admin? : <%= check_box_tag "person[admin]", "1", @person.company.admin? %>
Biography : <%= text_area :person, :biography %>
Last name : <%= f.text_field :last_name %>
First name: <%= f.text_field :first_name %>
<%= form_for :person do |f| %>

from FormTagHelper. For example:
possible to use both the stand-alone FormHelper methods and methods
Also note that +form_for+ doesn't create an exclusive scope. It's still

* :html - Optional HTML attributes for the form tag.
utf8 is not output.
* :enforce_utf8 - If set to false, a hidden input with name
behavior is an ajax submit.
JavaScript drivers to control the submit behavior. By default this
* :remote - If set to true, will allow the Unobtrusive
unnecessary unless you support browsers without JavaScript.
get the authenticity token from the meta tag, so embedding is
This is helpful when you're fragment-caching the form. Remote forms
config.action_view.embed_authenticity_token_in_remote_forms = false.
Remote forms may omit the embedded authenticity token by setting
not add authenticity_token field at all (by passing false).
Use only if you need to pass custom authenticity token string, or to
* :authenticity_token - Authenticity token to use in the form.
simulate the verb over post.
is used, a hidden input with name _method is added to
either "get" or "post". If "patch", "put", "delete", or another verb
* :method - The method to use when submitting the form, usually
with underscore on the generated HTML id.
id attributes on form elements. The namespace attribute will be prefixed
* :namespace - A namespace for your form to ensure uniqueness of
to be specified explicitly).
resource-oriented usage of +form_for+ in which the URL does not need
sent back to the current URL (We will describe below an alternative
:url option is not specified, by default the form will be
represented by a string or symbol, as in the example above, if the
So for example you may use a named route directly. When the model is
represented in the same way as values passed to +url_for+ or +link_to+.
* :url - The URL the form is to be submitted to. This may be

optional hash of options -
The rightmost argument to +form_for+ is an

@person.
existing record) will be the value of the corresponding attribute of
initially displayed (e.g. in the situation where you are editing an
@person, the default value of the field shown when the form is
if :person also happens to be the name of an instance variable
For fields generated in this way using the FormBuilder,

params[:person][:first_name].
the value entered by the user will be available in the controller as
person[first_name]. This means that when the form is submitted,
which results in an HTML tag whose +name+ attribute is

<%= text_field :person, :first_name %>

will get expanded to

<%= f.text_field :first_name %>

are used to generate fields bound to this model. Thus, for example,
:person passed to +form_for+. Methods defined on the FormBuilder
incorporates the knowledge about the model object represented by
The variable +f+ yielded to the block is a FormBuilder object that

<% end %>
<%= f.submit %>
Admin? : <%= f.check_box :admin %>

Biography : <%= f.text_area :biography %>

Last name : <%= f.text_field :last_name %>

First name: <%= f.text_field :first_name %>

<%= form_for :person do |f| %>

the object we are concerned with:
can be created by passing +form_for+ a string or symbol representing
how the form should be constructed. For a generic model object, a form
how much you wish to rely on Rails to infer automatically from the model
The method can be used in several slightly different ways, depending on

of a specific model object.
Creates a form that allows the user to create or update the attributes
def form_for(record, options = {}, &block)
  raise ArgumentError, "Missing block" unless block_given?
  html_options = options[:html] ||= {}
  case record
  when String, Symbol
    object_name = record
    object      = nil
  else
    object      = record.is_a?(Array) ? record.last : record
    raise ArgumentError, "First argument in form cannot contain nil or be empty" unless object
    object_name = options[:as] || model_name_from_record_or_class(object).param_key
    apply_form_for_options!(record, object, options)
  end
  html_options[:data]   = options.delete(:data)   if options.has_key?(:data)
  html_options[:remote] = options.delete(:remote) if options.has_key?(:remote)
  html_options[:method] = options.delete(:method) if options.has_key?(:method)
  html_options[:enforce_utf8] = options.delete(:enforce_utf8) if options.has_key?(:enforce_utf8)
  html_options[:authenticity_token] = options.delete(:authenticity_token)
  builder = instantiate_builder(object_name, object, options)
  output  = capture(builder, &block)
  html_options[:multipart] ||= builder.multipart?
  html_options = html_options_for_form(options[:url] || {}, html_options)
  form_tag_with_body(html_options, output)
end

def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)

end
form_with(**options.merge(builder: LabellingFormBuilder), &block)
def labelled_form_with(**options, &block)

could do something like the following:
In many cases you will want to wrap the above in another helper, so you

of a nested +fields+ call, unless it's explicitly set.
The custom FormBuilder class is automatically merged with the options

labelling_form.
variable referencing the form builder is called
The rendered template is people/_labelling_form and the local

<%= render form %>

In this case, if you use:

<% end %>
<%= form.submit %>
<%= form.check_box :admin %>
<%= form.text_area :biography %>
<%= form.text_field :last_name %>
<%= form.text_field :first_name %>
<%= form_with model: @person, url: { action: "create" }, builder: LabellingFormBuilder do |form| %>

automatically add labels to form inputs.
custom builder. For example, let's say you made a helper to
FormBuilder and override or define some more helpers, then use your
You can also build forms using a customized FormBuilder class. Subclass

=== Customized form builders

<% end %>
<% end %>
...
<%= form.fields(:comments, skip_id: true) do |fields| %>
<%= form_with(model: @post) do |form| %>

thus there is no primary key for comments.
In the following example the Post model has many Comments stored within it in a NoSQL database,

to disable the hidden id.
Some ORM systems do not use IDs on nested models so in this case you want to be able
This is used to maintain the correlation between the form data and its associated model.
The +form_with+ method automatically includes the model id as a hidden field in the form.

=== Removing hidden model id's


...



generates

<% end %>
...
<%= form_with(model: @post, data: { behavior: "autosave" }, html: { name: "go" }) do |form| %>

besides id and class must be wrapped in an HTML key:
You can set data attributes directly in a data hash, but HTML options

=== Setting HTML options

called _method will carry the intended verb for the server to interpret.
supported by HTML forms, the form will be set to POST and a hidden input
in the options hash. If the verb is not GET or POST, which are natively

method: (:get|:post|:patch|:put|:delete)

You can force the form to use the full array of HTTP verbs by setting

=== Setting the method

FormOptionsHelper#collection_select and DateHelper#datetime_select.
to work with an object as a base, like
Same goes for the methods in FormOptionsHelper and DateHelper designed

<% end %>
<%= form.submit %>

<%= check_box_tag "person[admin]", "1", @person.company.admin? %>
<%= text_area :person, :biography %>

<%= form.text_field :last_name %>
<%= form.text_field :first_name %>
<%= form_with scope: :person do |form| %>

from FormTagHelper:
match the stand-alone FormHelper methods and methods
While +form_with+ uses a FormBuilder object it's possible to mix and

=== Mixing with other form helpers

Where @document = Document.find(params[:id]).

<% end %>
...
<%= form_with(model: [ @document, Comment.new ]) do |form| %>

to the document given that the routes are set correctly:
If your resource has associations defined, for example, you want to add comments

<% end %>
...
<%= form_with(model: [ :admin, @post ]) do |form| %>

For namespaced routes, like +admin_post_url+:

<%= form_with(model: @post, authenticity_token: false) %> # Disables the token.
<%= form_with(model: @post, format: :json) %>
<%= form_with(model: @post, scope: :article) %>
<%= form_with(model: @post, url: super_posts_path) %>

When not passing a block, +form_with+ just generates an opening form tag.

=== Examples

* :html - Other optional HTML attributes for the form tag.
* :data - Optional HTML data attributes.
* :class - Optional HTML class attribute.
* :id - Optional HTML id attribute.
* :builder - Override the object used to build the form.
utf8 is not output.
* :skip_enforcing_utf8 - If set to true, a hidden input with name
Disable remote submits with local: true.
* :local - By default form submits are remote and unobtrusive XHRs.
unnecessary unless you support browsers without JavaScript.
get the authenticity token from the meta tag, so embedding is
This is helpful when fragment-caching the form. Remote forms
config.action_view.embed_authenticity_token_in_remote_forms = false.
Remote forms may omit the embedded authenticity token by setting
that might limit the valid fields.
Useful when submitting to an external resource like a payment gateway
skip the authenticity token field altogether.
Override with a custom authenticity token or pass false to
* :authenticity_token - Authenticity token to use in the form.
E.g. turn params[:post] into params[:article].
Pass :scope or :url to override the defaults.
existing record, however, an update form is generated.
If the model is a new record a create form is generated, if an
field's value would be "Ahoy!".
So if a +title+ attribute is set to "Ahoy!" then a +title+ input
:scope by, plus fill out input field values.
* :model - A model object to infer the :url and
with underscore on the generated HTML id.
id attributes on form elements. The namespace attribute will be prefixed
* :namespace - A namespace for your form to ensure uniqueness of
thereby how the submitted parameters are grouped in controllers.
* :scope - The scope to prefix input field names with and
Skipped if a :url is passed.
Useful when submitting to another resource type, like :json.
* :format - The format of the route the form submits to.
simulate the verb over post.
is used, a hidden input named _method is added to
either "get" or "post". If "patch", "put", "delete", or another verb
* :method - The method to use when submitting the form, usually
form just submits to the current URL.
directly. When a :scope is passed without a :url the
+url_for+ or +link_to+. For example, you may use a named route
* :url - The URL the form submits to. Akin to values passed to

==== +form_with+ options

<% end %>
...
<%= form_with scope: :post, url: posts_path do |form| %>

is equivalent to something like:

<% end %>
...
<%= form_with model: Post.new do |form| %>

And for a new record

<% end %>
...
<%= form_with scope: :post, url: post_path(@post), method: :patch do |form| %>

is then equivalent to something like:

<% end %>
...
<%= form_with model: @post do |form| %>

So when passing such a model record, Rails infers the URL and method.

defined via +resources+ in config/routes.rb.
is a _resource_. It corresponds to a set of RESTful routes, most likely
In many of the examples just shown, the +:model+ passed to +form_with+

=== Resource-oriented style

protection.
and adds an authenticity token needed for cross site request forgery
as well as the auto generated hidden fields that enable UTF-8 support
For ease of comparison the examples above left out the submit button,

:local option for more.
Unobtrusive JavaScript driver, like rails-ujs, is used. See the
submitting the form via an XMLHTTPRequest in the background if an
By default +form_with+ attaches the data-remote attribute

respectively.
accessible as params[:title] and params[:post][:title]
their name nesting. So inputs named +title+ and post[title] are
The parameters in the forms are accessible in controllers according to





# =>
<% end %>
<%= form.text_field :but_in_forms_they_can %>
<%= form.text_field :cats_dont_have_gills %>
<%= form_with model: Cat.new do |form| %>
# Though the fields don't have to correspond to model attributes:





# =>
<% end %>
<%= form.text_field :title %>
<%= form_with model: Post.first do |form| %>
# An existing model makes an update form and fills out field values:




# =>
<% end %>
<%= form.text_field :title %>
<%= form_with model: Post.new do |form| %>
# Using a model infers both the URL and scope:




# =>
<% end %>
<%= form.text_field :title %>
<%= form_with scope: :post, url: posts_path do |form| %>
# Adding a scope prefixes the input field names:




# =>
<% end %>
<%= form.text_field :title %>
<%= form_with url: posts_path do |form| %>
# Using just a URL:

Creates a form tag based on mixing URLs, scopes, or models.
def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)
  options[:allow_method_names_outside_object] = true
  options[:skip_default_ids] = !form_with_generates_ids
  if model
    url ||= polymorphic_path(model, format: format)
    model   = model.last if model.is_a?(Array)
    scope ||= model_name_from_record_or_class(model).param_key
  end
  if block_given?
    builder = instantiate_builder(scope, model, options)
    output  = capture(builder, &block)
    options[:multipart] ||= builder.multipart?
    html_options = html_options_for_form_with(url, model, **options)
    form_tag_with_body(html_options, output)
  else
    html_options = html_options_for_form_with(url, model, **options)
    form_tag_html(html_options)
  end
end

def hidden_field(object_name, method, options = {})

# =>
hidden_field(:user, :token)

# =>
hidden_field(:post, :tag_list)

# =>
hidden_field(:signup, :pass_confirm)
==== Examples

shown.
hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
assigned to the template (identified by +object+). Additional options on the input tag can be passed as a
Returns a hidden input tag tailored for accessing a specified attribute (identified by +method+) on an object
def hidden_field(object_name, method, options = {})
  Tags::HiddenField.new(object_name, method, self, options).render
end

def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: !form_with_generates_remote_forms,

def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: !form_with_generates_remote_forms,
  skip_enforcing_utf8: nil, **options)
  html_options = options.slice(:id, :class, :multipart, :method, :data).merge(html)
  html_options[:method] ||= :patch if model.respond_to?(:persisted?) && model.persisted?
  html_options[:enforce_utf8] = !skip_enforcing_utf8 unless skip_enforcing_utf8.nil?
  html_options[:enctype] = "multipart/form-data" if html_options.delete(:multipart)
  # The following URL is unescaped, this is just a hash of options, and it is the
  # responsibility of the caller to escape all the values.
  html_options[:action] = url_for(url_for_options || {})
  html_options[:"accept-charset"] = "UTF-8"
  html_options[:"data-remote"] = true unless local
  html_options[:authenticity_token] = options.delete(:authenticity_token)
  if !local && html_options[:authenticity_token].blank?
    html_options[:authenticity_token] = embed_authenticity_token_in_remote_forms
  end
  if html_options[:authenticity_token] == true
    # Include the default authenticity_token, which is only generated when it's set to nil,
    # but we needed the true value to override the default of no authenticity_token on data-remote.
    html_options[:authenticity_token] = nil
  end
  html_options.stringify_keys!
end

def instantiate_builder(record_name, record_object, options)

def instantiate_builder(record_name, record_object, options)
  case record_name
  when String, Symbol
    object = record_object
    object_name = record_name
  else
    object = record_name
    object_name = model_name_from_record_or_class(object).param_key if object
  end
  builder = options[:builder] || default_form_builder_class
  builder.new(object_name, object, self, options)
end

def label(object_name, method, content_or_options = nil, options = nil, &block)

# =>
end
raw('Accept Terms.')
label(:post, :terms) do

# =>
label(:post, :privacy, "Public Post", value: "public")

# =>
label(:post, :title, "A short title", class: "title_label")

# =>
label(:post, :title, "A short title")

# =>
label(:post, :cost)

cost: "Total cost"
post:
attributes:
activerecord:

(if you are using ActiveRecord):
Localization can also be based purely on the translation of the attribute-name

# =>
label(:post, :body)

Which then will result in

body: "Write your entire text here"
post:
label:
helpers:

For example you can define the following in your locale (e.g. en.yml)
You can localize your labels based on model and attribute names.

# =>
label(:post, :title)
==== Examples

target labels for radio_button tags (where the value is used in the ID of the input tag).
onto the HTML as an HTML element attribute as in the example shown, except for the :value option, which is designed to
Additional options on the label tag can be passed as a hash with +options+. These options will be tagged
is found in the current I18n locale (through helpers.label..) or you specify it explicitly.
assigned to the template (identified by +object+). The text of label will default to the attribute name unless a translation
Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object
def label(object_name, method, content_or_options = nil, options = nil, &block)
  Tags::Label.new(object_name, method, self, content_or_options, options).render(&block)
end

def month_field(object_name, method, options = {})


# =>
month_field("user", "born_on")
@user.born_on = Date.new(1984, 1, 27)

of DateTime and ActiveSupport::TimeWithZone.
on the object's value, which makes it behave as expected for instances
The default value is generated by trying to call +strftime+ with "%Y-%m"

# =>
month_field("user", "born_on")

Returns a text_field of type "month".
def month_field(object_name, method, options = {})
  Tags::MonthField.new(object_name, method, self, options).render
end

def number_field(object_name, method, options = {})

* Accepts same options as number_field_tag
==== Options

Returns an input tag of type "number".
def number_field(object_name, method, options = {})
  Tags::NumberField.new(object_name, method, self, options).render
end

def password_field(object_name, method, options = {})

# =>
password_field(:account, :pin, size: 20, class: 'form_input')

# =>
password_field(:user, :password, onchange: "if ($('#user_password').val().length > 30) { alert('Your password needs to be shorter!'); }")

# =>
password_field(:account, :secret, class: "form_input", value: @account.secret)

# =>
password_field(:login, :pass, size: 20)
==== Examples

shown. For security reasons this field is blank by default; pass in a value via +options+ if this is not desired.
hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
assigned to the template (identified by +object+). Additional options on the input tag can be passed as a
Returns an input tag of the "password" type tailored for accessing a specified attribute (identified by +method+) on an object
def password_field(object_name, method, options = {})
  Tags::PasswordField.new(object_name, method, self, options).render
end

def radio_button(object_name, method, tag_value, options = {})

#
# =>
radio_button("user", "receive_newsletter", "no")
radio_button("user", "receive_newsletter", "yes")
# Let's say that @user.receive_newsletter returns "no":

#
# =>
radio_button("post", "category", "java")
radio_button("post", "category", "rails")
# Let's say that @post.category returns "rails":

+options+ hash. You may pass HTML options there as well.
To force the radio button to be checked pass checked: true in the

radio button will be checked.
assigned to the template (identified by +object+). If the current value of +method+ is +tag_value+ the
Returns a radio button tag for accessing a specified attribute (identified by +method+) on an object
def radio_button(object_name, method, tag_value, options = {})
  Tags::RadioButton.new(object_name, method, self, tag_value, options).render
end

def range_field(object_name, method, options = {})

* Accepts same options as range_field_tag
==== Options

Returns an input tag of type "range".
def range_field(object_name, method, options = {})
  Tags::RangeField.new(object_name, method, self, options).render
end

def search_field(object_name, method, options = {})

# =>
search_field(:user, :name, autosave: true, onsearch: true)
# =>
search_field(:user, :name, autosave: false, onsearch: true)
# =>
search_field(:user, :name, onsearch: true)
# =>
search_field(:user, :name, autosave: true)
# Assume request.host returns "www.example.com"
# =>
search_field(:user, :name, results: 3)
# =>
search_field(:user, :name, autosave: false)
# =>
search_field(:user, :name)

some browsers.
assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by
Returns an input of type "search" for accessing a specified attribute (identified by +method+) on an object
def search_field(object_name, method, options = {})
  Tags::SearchField.new(object_name, method, self, options).render
end

def telephone_field(object_name, method, options = {})


# =>
telephone_field("user", "phone")

Returns a text_field of type "tel".
def telephone_field(object_name, method, options = {})
  Tags::TelField.new(object_name, method, self, options).render
end

def text_area(object_name, method, options = {})

#
# #{@entry.body}
# =>
# #{@application.notes}
# =>
# #{@comment.text}
# =>
# #{@post.body}
# =>