class ActionView::Helpers::FormBuilder
def self._to_partial_path
def self._to_partial_path @_to_partial_path ||= name.demodulize.underscore.sub!(/_builder$/, "") end
def button(value = nil, options = {}, &block)
#
# Save as draft
# =>
# Create post
# =>
# Ask me!
# =>
def button(value = nil, options = {}, &block) case value when Hash value, options = nil, value when Symbol value, options = nil, { name: field_name(value), id: field_id(value) }.merge!(options.to_h) end value ||= submit_default_value if block_given? value = @template.capture { yield(value) } end formmethod = options[:formmethod] if formmethod.present? && !/post|get/i.match?(formmethod) && !options.key?(:name) && !options.key?(:value) options.merge! formmethod: :post, name: "_method", value: formmethod end @template.button_tag(value, options) end
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
# =>
check_box("accepted", { class: 'eula_check' }, "yes", "no")
# Let's say that @eula.accepted is "no":
#
# =>
check_box("gooddog", {}, "yes", "no")
# Let's say that @puppy.gooddog is "no":
#
# =>
check_box("validated")
# Let's say that @post.validated? is 1:
==== Examples
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.
every 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
* :include_hidden - If set to false, the auxiliary hidden field described below will not be generated.
* :checked - +true+ or +false+ forces the state of the checkbox to be checked or not.
* Any standard HTML attributes for the tag can be passed in, for example +:class+.
==== Options
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(method, options = {}, checked_value = "1", unchecked_value = "0") @template.check_box(@object_name, method, objectify_options(options), checked_value, unchecked_value) end
def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
<% end %>
<%= f.submit %>
<%= f.collection_check_boxes :author_ids, Author.all, :id, :name_with_initial %>
<%= form_for @post do |f| %>
Wraps ActionView::Helpers::FormOptionsHelper#collection_check_boxes for form builders:
def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block) @template.collection_check_boxes(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block) end
def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
<% end %>
<%= f.submit %>
<%= f.collection_radio_buttons :author_id, Author.all, :id, :name_with_initial %>
<%= form_for @post do |f| %>
Wraps ActionView::Helpers::FormOptionsHelper#collection_radio_buttons for form builders:
def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block) @template.collection_radio_buttons(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options), &block) end
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
<% end %>
<%= f.submit %>
<%= f.collection_select :person_id, Author.all, :id, :name_with_initial, prompt: true %>
<%= form_for @post do |f| %>
Wraps ActionView::Helpers::FormOptionsHelper#collection_select for form builders:
def collection_select(method, collection, value_method, text_method, options = {}, html_options = {}) @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_html_options.merge(html_options)) end
def convert_to_legacy_options(options)
def convert_to_legacy_options(options) if options.key?(:skip_id) options[:include_id] = !options.delete(:skip_id) end end
def date_select(method, options = {}, html_options = {})
<% end %>
<%= f.submit %>
<%= f.date_select :birth_date %>
<%= form_for @person do |f| %>
Wraps ActionView::Helpers::DateHelper#date_select for form builders:
def date_select(method, options = {}, html_options = {}) @template.date_select(@object_name, method, objectify_options(options), html_options) end
def datetime_select(method, options = {}, html_options = {})
<% end %>
<%= f.submit %>
<%= f.datetime_select :last_request_at %>
<%= form_for @person do |f| %>
Wraps ActionView::Helpers::DateHelper#datetime_select for form builders:
def datetime_select(method, options = {}, html_options = {}) @template.datetime_select(@object_name, method, objectify_options(options), html_options) end
def emitted_hidden_id? # :nodoc:
def emitted_hidden_id? # :nodoc: @emitted_hidden_id ||= nil end
def field_id(method, *suffixes, namespace: @options[:namespace], index: @options[:index])
element, sharing a common id root (post_title, in this
aria-describedby attribute referencing the
the call to FormBuilder#text_field declares an
In the example above, the element built by
<% end %>
<%= tag.span("is blank", id: f.field_id(:title, :error) %>
<%= f.text_field :title, aria: { describedby: f.field_id(:title, :error) } %>
<%= f.label :title %>
<%= form_for @post do |f| %>
attribute name.
Return the value generated by the FormBuilder for the given
Generate an HTML id attribute value for the given field
def field_id(method, *suffixes, namespace: @options[:namespace], index: @options[:index]) @template.field_id(@object_name, method, *suffixes, namespace: namespace, index: index) end
def field_name(method, *methods, multiple: false, index: @options[:index])
<% end %>
<%# => %>
<%= f.text_field :tag, name: f.field_name(:tag, multiple: true) %>
<%= form_for @post do |f| %>
<% end %>
<%# => %>
<%= f.text_field :title, name: f.field_name(:title, :subtitle) %>
<%= form_for @post do |f| %>
attribute name.
Return the value generated by the FormBuilder for the given
field combination
Generate an HTML name attribute value for the given name and
def field_name(method, *methods, multiple: false, index: @options[:index]) object_name = @options.fetch(:as) { @object_name } @template.field_name(object_name, method, *methods, index: index, multiple: multiple) end
def fields(scope = nil, model: nil, **options, &block)
def fields(scope = nil, model: nil, **options, &block) options[:allow_method_names_outside_object] = true options[:skip_default_ids] = !FormHelper.form_with_generates_ids convert_to_legacy_options(options) fields_for(scope || model, model, options, &block) end
def fields_for(record_name, record_object = nil, fields_options = nil, &block)
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 in 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| %>
(e.g. 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 (e.g. 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
<% end %>
...
<% end %>
Admin?: <%= check_box_tag permission_fields.field_name(:admin), @person.permission[:admin] %>
<%= fields_for :permission, @person.permission, {} do |permission_fields| %>
...
<%= form_for @person do |person_form| %>
option Hash. To remove the ambiguity, explicitly pass an option Hash, even if empty.
name and value parameters are provided and the provided value has the shape of an
+fields_for+ tries to be smart about parameters, but it can be confused if both
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, fields_options = nil, &block) fields_options, record_object = record_object, nil if fields_options.nil? && record_object.is_a?(Hash) && record_object.extractable_options? fields_options ||= {} fields_options[:builder] ||= options[:builder] fields_options[:namespace] = options[:namespace] fields_options[:parent_builder] = self case record_name when String, Symbol if nested_attributes_association?(record_name) return fields_for_with_nested_attributes(record_name, record_object, fields_options, block) end else record_object = @template._object_for_form_builder(record_name) record_name = model_name_from_record_or_class(record_object).param_key end object_name = @object_name index = if options.has_key?(:index) options[:index] elsif defined?(@auto_index) object_name = object_name.to_s.delete_suffix("[]") @auto_index end record_name = if index "#{object_name}[#{index}][#{record_name}]" elsif record_name.end_with?("[]") "#{object_name}[#{record_name[0..-3]}][#{record_object.id}]" else "#{object_name}[#{record_name}]" end fields_options[:child_index] = index @template.fields_for(record_name, record_object, fields_options, &block) end
def fields_for_nested_model(name, object, fields_options, block)
def fields_for_nested_model(name, object, fields_options, block) object = convert_to_model(object) emit_hidden_id = object.persisted? && fields_options.fetch(:include_id) { options.fetch(:include_id, true) } @template.fields_for(name, object, fields_options) do |f| output = @template.capture(f, &block) output.concat f.hidden_field(:id) if output && emit_hidden_id && !f.emitted_hidden_id? output end end
def fields_for_with_nested_attributes(association_name, association, options, block)
def fields_for_with_nested_attributes(association_name, association, options, block) name = "#{object_name}[#{association_name}_attributes]" association = convert_to_model(association) if association.respond_to?(:persisted?) association = [association] if @object.public_send(association_name).respond_to?(:to_ary) elsif !association.respond_to?(:to_ary) association = @object.public_send(association_name) end if association.respond_to?(:to_ary) explicit_child_index = options[:child_index] output = ActiveSupport::SafeBuffer.new association.each do |child| if explicit_child_index options[:child_index] = explicit_child_index.call if explicit_child_index.respond_to?(:call) else options[:child_index] = nested_child_index(name) end if content = fields_for_nested_model("#{name}[#{options[:child_index]}]", child, options, block) output << content end end output elsif association fields_for_nested_model(name, association, options, block) end end
def file_field(method, options = {})
file_field(:file, class: 'file_input')
# Let's say that @attachment has file:
# =>
file_field(:image, accept: 'image/png,image/gif,image/jpeg')
# Let's say that @post has image:
# =>
file_field(:attached, accept: 'text/html')
# Let's say that @post has attached:
# =>
file_field(:image, :multiple => true)
# Let's say that @post has image:
# =>
file_field(:avatar)
# Let's say that @user has 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.
* :include_hidden - When multiple: true and include_hidden: true, the field will be prefixed with an field with an empty value to support submitting an empty collection of files. Since include_hidden will default to config.active_storage.multiple_file_field_include_hidden if you don't specify include_hidden, you will need to pass include_hidden: false to prevent submitting an empty collection of files when passing multiple: true.
* :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_with+ 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(method, options = {}) self.multipart = true @template.file_field(@object_name, method, objectify_options(options)) end
def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
<% end %>
<%= f.submit %>
<%= f.grouped_collection_select :country_id, @continents, :countries, :name, :id, :name %>
<%= form_for @city do |f| %>
Wraps ActionView::Helpers::FormOptionsHelper#grouped_collection_select for form builders:
def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_html_options.merge(html_options)) end
def hidden_field(method, options = {})
# =>
hidden_field(:token)
# Let's say that @user.token returns "abcde":
# =>
hidden_field(:tag_list)
# Let's say that @post.tag_list returns "blog, ruby":
# =>
hidden_field(:pass_confirm)
# Let's say that @signup.pass_confirm returns true:
==== 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(method, options = {}) @emitted_hidden_id = true if method == :id @template.hidden_field(@object_name, method, objectify_options(options)) end
def id
form HTML attribute, we hint to the browser that the generated
exist outside of the element. By declaring the
In the example above, the :sticky_footer content area will
<% end %>
<% end %>
<%= form.button(form: f.id) %>
<% content_for :sticky_footer do %>
<%# ... %>
<%= form_for @post do |f| %>
return the element's id attribute.
Generate an HTML id attribute value.
def id options.dig(:html, :id) || options[:id] end
def initialize(object_name, object, template, options)
def initialize(object_name, object, template, options) @nested_child_index = {} @object_name, @object, @template, @options = object_name, object, template, options @default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids, :allow_method_names_outside_object) : {} @default_html_options = @default_options.except(:skip_default_ids, :allow_method_names_outside_object) convert_to_legacy_options(@options) if @object_name&.end_with?("[]") if (object ||= @template.instance_variable_get("@#{@object_name[0..-3]}")) && object.respond_to?(:to_param) @auto_index = object.to_param else raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}" end end @multipart = nil @index = options[:index] || options[:child_index] end
def label(method, text = nil, options = {}, &block)
end
raw('Accept Terms.')
label(:terms) do
# =>
end
])
("error_label" if builder.object.errors.include?(:cost))
"cost_label",
content_tag(:span, builder.translation, class: [
label(:cost) do |builder|
# =>
end
content_tag(:span, builder.translation, class: "cost_label")
label(:cost) do |builder|
# =>
end
content_tag(:span, translation, class: "cost_label")
label(:cost) do |translation|
# =>
label(:privacy, "Public Post", value: "public")
# =>
label(:title, "A short title", class: "title_label")
# =>
label(:title, "A short title")
# =>
label(: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(: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(: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.
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(method, text = nil, options = {}, &block) @template.label(@object_name, method, text, objectify_options(options), &block) end
def multipart=(multipart)
def multipart=(multipart) @multipart = multipart if parent_builder = @options[:parent_builder] parent_builder.multipart = multipart end end
def nested_attributes_association?(association_name)
def nested_attributes_association?(association_name) @object.respond_to?("#{association_name}_attributes=") end
def nested_child_index(name)
def nested_child_index(name) @nested_child_index[name] ||= -1 @nested_child_index[name] += 1 end
def objectify_options(options)
def objectify_options(options) result = @default_options.merge(options) result[:object] = @object result end
def radio_button(method, tag_value, options = {})
# =>
radio_button("receive_newsletter", "no")
radio_button("receive_newsletter", "yes")
# Let's say that @user.receive_newsletter returns "no":
#
# =>
radio_button("category", "java")
radio_button("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(method, tag_value, options = {}) @template.radio_button(@object_name, method, tag_value, objectify_options(options)) end
def select(method, choices = nil, options = {}, html_options = {}, &block)
<% end %>
<%= f.submit %>
<%= f.select :person_id, Person.all.collect { |p| [ p.name, p.id ] }, include_blank: true %>
<%= form_for @post do |f| %>
Wraps ActionView::Helpers::FormOptionsHelper#select for form builders:
def select(method, choices = nil, options = {}, html_options = {}, &block) @template.select(@object_name, method, choices, objectify_options(options), @default_html_options.merge(html_options), &block) end
def submit(value = nil, options = {})
create: "Add %{model}"
post:
submit:
helpers:
en:
It also searches for a key specific to the given object:
update: "Confirm changes to %{model}"
create: "Create a %{model}"
submit:
helpers:
en:
%{model} for translation interpolation:
Those labels can be customized using I18n under the +helpers.submit+ key and using
submit button label; otherwise, it uses "Update Post".
In the example above, if @post is a new record, it will use "Create Post" as
<% end %>
<%= f.submit %>
<%= form_for @post do |f| %>
if the object is a new resource or not to create the proper label:
Add the submit button for the given form. When no value is given, it checks
def submit(value = nil, options = {}) value, options = nil, value if value.is_a?(Hash) value ||= submit_default_value @template.submit_tag(value, options) end
def submit_default_value
def submit_default_value object = convert_to_model(@object) key = object ? (object.persisted? ? :update : :create) : :submit model = if object.respond_to?(:model_name) object.model_name.human else @object_name.to_s.humanize end defaults = [] # Object is a model and it is not overwritten by as and scope option. if object.respond_to?(:model_name) && object_name.to_s == model.downcase defaults << :"helpers.submit.#{object.model_name.i18n_key}.#{key}" else defaults << :"helpers.submit.#{object_name}.#{key}" end defaults << :"helpers.submit.#{key}" defaults << "#{key.to_s.humanize} #{model}" I18n.t(defaults.shift, model: model, default: defaults) end
def time_select(method, options = {}, html_options = {})
<% end %>
<%= f.submit %>
<%= f.time_select :average_lap %>
<%= form_for @race do |f| %>
Wraps ActionView::Helpers::DateHelper#time_select for form builders:
def time_select(method, options = {}, html_options = {}) @template.time_select(@object_name, method, objectify_options(options), html_options) end
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
<% end %>
<%= f.submit %>
<%= f.time_zone_select :time_zone, nil, include_blank: true %>
<%= form_for @user do |f| %>
Wraps ActionView::Helpers::FormOptionsHelper#time_zone_select for form builders:
def time_zone_select(method, priority_zones = nil, options = {}, html_options = {}) @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_html_options.merge(html_options)) end
def to_model
def to_model self end
def to_partial_path
def to_partial_path self.class._to_partial_path end
def weekday_select(method, options = {}, html_options = {})
<% end %>
<%= f.submit %>
<%= f.weekday_select :weekday, include_blank: true %>
<%= form_for @user do |f| %>
Wraps ActionView::Helpers::FormOptionsHelper#weekday_select for form builders:
def weekday_select(method, options = {}, html_options = {}) @template.weekday_select(@object_name, method, objectify_options(options), @default_html_options.merge(html_options)) end