class SimpleForm::FormBuilder

def self.discovery_cache

def self.discovery_cache
  @discovery_cache ||= {}
end

def association(association, options = {}, &block)


Please note that the association helper is currently only tested with Active Record. Depending on the ORM you are using your mileage may vary.

From the options above, only :collection can also be supplied.

end
c.input :type
c.input :name
f.association :company do |c|

simple_fields_for:
When a block is given, association simple behaves as a proxy to

== Block

# Same as using :order option, but overriding collection
f.association :company, collection: Company.all(order: 'name')

end
f.association :company # Company.all
simple_form_for @user do |f|

== Examples

can also be given:
supported in input are also supported by association. Some extra options
collection automatically. It's just a wrapper to input, so all options
Helper for dealing with association selects/radios, generating the
def association(association, options = {}, &block)
  options = options.dup
  return simple_fields_for(*[association,
    options.delete(:collection), options].compact, &block) if block_given?
  raise ArgumentError, "Association cannot be used in forms not associated with an object" unless @object
  reflection = find_association_reflection(association)
  raise "Association #{association.inspect} not found" unless reflection
  options[:as] ||= :select
  options[:collection] ||= fetch_association_collection(reflection, options)
  attribute = build_association_attribute(reflection, association, options)
  input(attribute, options.merge(reflection: reflection))
end

def attempt_mapping(mapping, at)

def attempt_mapping(mapping, at)
  return if SimpleForm.inputs_discovery == false && at == Object
  begin
    at.const_get(mapping)
  rescue NameError => e
    raise unless e.message.include?(mapping)
  end
end

def attempt_mapping_with_custom_namespace(input_name)

def attempt_mapping_with_custom_namespace(input_name)
  SimpleForm.custom_inputs_namespaces.each do |namespace|
    if (mapping = attempt_mapping(input_name, namespace.constantize))
      return mapping
    end
  end
  nil
end

def build_association_attribute(reflection, association, options)

def build_association_attribute(reflection, association, options)
  case reflection.macro
  when :belongs_to
    (reflection.respond_to?(:options) && reflection.options[:foreign_key]) || :"#{reflection.name}_id"
  when :has_one
    raise ArgumentError, ":has_one associations are not supported by f.association"
  else
    if options[:as] == :select || options[:as] == :grouped_select
      html_options = options[:input_html] ||= {}
      html_options[:multiple] = true unless html_options.key?(:multiple)
    end
    # Force the association to be preloaded for performance.
    if options[:preload] != false && object.respond_to?(association)
      target = object.send(association)
      target.to_a if target.respond_to?(:to_a)
    end
    :"#{reflection.name.to_s.singularize}_ids"
  end
end

def build_input_field_components(components)

def build_input_field_components(components)
  components.map do |component|
    if component == :input
      SimpleForm::Wrappers::Leaf.new(component, build_input_field_options)
    else
      SimpleForm::Wrappers::Leaf.new(component)
    end
  end
end

def build_input_field_options

def build_input_field_options
  input_field_options = {}
  valid_class         = SimpleForm.input_field_valid_class
  error_class         = SimpleForm.input_field_error_class
  if error_class.present?
    input_field_options[:error_class] = error_class
  end
  if valid_class.present?
    input_field_options[:valid_class] = valid_class
  end
  input_field_options
end

def button(type, *args, &block)

def button(type, *args, &block)
  options = args.extract_options!.dup
  options[:class] = [SimpleForm.button_class, options[:class]].compact
  args << options
  if respond_to?(:"#{type}_button")
    send(:"#{type}_button", *args, &block)
  else
    send(type, *args, &block)
  end
end

def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)

* a block => to generate the label + check box or any other component.

* item_wrapper_class => the CSS class to use for item_wrapper_tag

* item_wrapper_tag => the tag to wrap each item in the collection.

is ignored if the :collection_wrapper_tag option is blank.
* collection_wrapper_class => the CSS class to use for collection_wrapper_tag. This option

* collection_wrapper_tag => the tag to wrap the entire collection.

item or an array of items.
* disabled => the value or values that should be disabled. Accepts a single

a single item or an array of items. It overrides existing associations.
* checked => the value or values that should be checked initially. Accepts

Collection check box accepts some extra options:

== Options

end
end
b.label { b.check_box + b.text }
) do |b|
:options, [[true, 'Yes'] ,[false, 'No']], :first, :last
f.collection_check_boxes(
form_for @user do |f|

label. To wrap the check box with the label, for instance:
It is also possible to give a block that should generate the check box +








end
f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
form_for @user do |f|

== Examples

that will be evaluated for each item in the collection.
You can give a symbol or a proc to both value_method and text_method,
convert items in the collection for use as text/value in check boxes.
associated with a clickable label. Use value_method and text_method to
Creates a collection of check boxes for each item in the collection,
def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
  SimpleForm::Tags::CollectionCheckBoxes.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
end

def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)

* a block => to generate the label + radio or any other component.

* item_wrapper_class => the CSS class to use for item_wrapper_tag

* item_wrapper_tag => the tag to wrap each item in the collection.

* collection_wrapper_class => the CSS class to use for collection_wrapper_tag

* collection_wrapper_tag => the tag to wrap the entire collection.

item or an array of items.
* disabled => the value or values that should be disabled. Accepts a single

* checked => the value that should be checked initially.

Collection radio accepts some extra options:

== Options

end
end
b.label { b.radio_button + b.text }
) do |b|
:options, [[true, 'Yes'] ,[false, 'No']], :first, :last
f.collection_radio_buttons(
form_for @user do |f|

label. To wrap the radio with the label, for instance:
It is also possible to give a block that should generate the radio +






end
f.collection_radio_buttons :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
form_for @user do |f|

== Examples

the collection.
value_method and text_method, that will be evaluated for each item in
to convert these text/value. You can give a symbol or a proc to both
text/value option in the collection, using value_method and text_method
helper will create a radio input associated with a label for each
Create a collection of radio inputs for the attribute. Basically this
def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
  SimpleForm::Tags::CollectionRadioButtons.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
end

def default_input_type(attribute_name, column, options)

collection is given.
default always fallback to the user :as option, or to a :select when a
Attempt to guess the better input type given the defined options. By
def default_input_type(attribute_name, column, options)
  return options[:as].to_sym if options[:as]
  custom_type = find_custom_type(attribute_name.to_s) and return custom_type
  return :select             if options[:collection]
  input_type = column.try(:type)
  case input_type
  when :timestamp
    :datetime
  when :string, :citext, nil
    case attribute_name.to_s
    when /(?:\b|\W|_)password(?:\b|\W|_)/  then :password
    when /(?:\b|\W|_)time_zone(?:\b|\W|_)/ then :time_zone
    when /(?:\b|\W|_)country(?:\b|\W|_)/   then :country
    when /(?:\b|\W|_)email(?:\b|\W|_)/     then :email
    when /(?:\b|\W|_)phone(?:\b|\W|_)/     then :tel
    when /(?:\b|\W|_)url(?:\b|\W|_)/       then :url
    else
      file_method?(attribute_name) ? :file : (input_type || :string)
    end
  else
    input_type
  end
end

def discovery_cache

between requests, otherwise use the instance one.
If cache_discovery is enabled, use the class level cache that persists
def discovery_cache
  if SimpleForm.cache_discovery
    self.class.discovery_cache
  else
    @discovery_cache ||= {}
  end
end

def error(attribute_name, options = {})


f.error :name, id: "cool_error"
f.error :name

== Examples

contains errors. All the given options are sent as :error_html.
Creates an error tag based on the given attribute, only when the attribute
def error(attribute_name, options = {})
  options = options.dup
  options[:error_html] = options.except(:error_tag, :error_prefix, :error_method)
  column      = find_attribute_column(attribute_name)
  input_type  = default_input_type(attribute_name, column, options)
  wrapper.find(:error).
    render(SimpleForm::Inputs::Base.new(self, attribute_name, column, input_type, options))
end

def error_notification(options = {})


f.error_notification id: 'user_error_message', class: 'form_error'
f.error_notification message: 'Something went wrong'
f.error_notification

== Examples

passed straight as html options to the html tag.
otherwise it will look for a message using I18n. All other options given are
has some error. You can give a specific message with the :message option,
Creates an error notification message that only appears when the form object
def error_notification(options = {})
  SimpleForm::ErrorNotification.new(self, options).render
end

def fetch_association_collection(reflection, options)

def fetch_association_collection(reflection, options)
  options.fetch(:collection) do
    relation = reflection.klass.all
    if reflection.respond_to?(:scope) && reflection.scope
      if reflection.scope.parameters.any?
        relation = reflection.klass.instance_exec(object, &reflection.scope)
      else
        relation = reflection.klass.instance_exec(&reflection.scope)
      end
    else
      order = reflection.options[:order]
      conditions = reflection.options[:conditions]
      conditions = object.instance_exec(&conditions) if conditions.respond_to?(:call)
      relation = relation.where(conditions) if relation.respond_to?(:where) && conditions.present?
      relation = relation.order(order) if relation.respond_to?(:order)
    end
    relation
  end
end

def file_method?(attribute_name)

Returns a Boolean.

- `#{attribute_name}_file_name` - Paperclip ~> `2.0` (added for backwards compatibility)
- `#{attribute_name}_attacher` - Refile >= `0.4.0` and Shrine >= `0.9.0`
- `remote_#{attribute_name}_url` - Refile >= `0.3.0` and CarrierWave >= `0.2.2`
- `#{attribute_name}_attachment` - ActiveStorage >= `5.2` and Refile >= `0.2.0` <= `0.4.0`

The order here was chosen based on the popularity of Gems:

Note: This does not support multiple file upload inputs, as this is very application-specific.

of their methods using `#respond_to?`.
This method tries to guess if an attribute belongs to some of these Gems by checking the presence
Most upload Gems add some kind of attributes to the ActiveRecord's model they are included in.

Internal: Try to discover whether an attribute corresponds to a file or not.
def file_method?(attribute_name)
  @object.respond_to?("#{attribute_name}_attachment") ||
    @object.respond_to?("#{attribute_name}_attachments") ||
    @object.respond_to?("remote_#{attribute_name}_url") ||
    @object.respond_to?("#{attribute_name}_attacher") ||
    @object.respond_to?("#{attribute_name}_file_name")
end

def find_association_reflection(association)

def find_association_reflection(association)
  if @object.class.respond_to?(:reflect_on_association)
    @object.class.reflect_on_association(association)
  end
end

def find_attribute_column(attribute_name)

def find_attribute_column(attribute_name)
  if @object.respond_to?(:type_for_attribute) && @object.has_attribute?(attribute_name)
    @object.type_for_attribute(attribute_name.to_s)
  elsif @object.respond_to?(:column_for_attribute) && @object.has_attribute?(attribute_name)
    @object.column_for_attribute(attribute_name)
  end
end

def find_custom_type(attribute_name)

def find_custom_type(attribute_name)
  SimpleForm.input_mappings.find { |match, type|
    attribute_name =~ match
  }.try(:last) if SimpleForm.input_mappings
end

def find_input(attribute_name, options = {}, &block)

Find an input based on the attribute name.
def find_input(attribute_name, options = {}, &block)
  column     = find_attribute_column(attribute_name)
  input_type = default_input_type(attribute_name, column, options)
  if block_given?
    SimpleForm::Inputs::BlockInput.new(self, attribute_name, column, input_type, options, &block)
  else
    find_mapping(input_type).new(self, attribute_name, column, input_type, options)
  end
end

def find_mapping(input_type)

3) If not, fallbacks to SimpleForm::Inputs::#{input_type}Input
2) If not, fallbacks to #{input_type}Input
b) Or use the found mapping
a) Try to find an alternative with the same name in the Object scope
1) It tries to find a registered mapping, if succeeds:

Attempts to find a mapping. It follows the following rules:
def find_mapping(input_type)
  discovery_cache[input_type] ||=
    if mapping = self.class.mappings[input_type]
      mapping_override(mapping) || mapping
    else
      camelized = "#{input_type.to_s.camelize}Input"
      attempt_mapping_with_custom_namespace(camelized) ||
        attempt_mapping(camelized, Object) ||
        attempt_mapping(camelized, self.class) ||
        raise("No input found for #{input_type}")
    end
end

def find_wrapper(input_type, options)

def find_wrapper(input_type, options)
  if name = options[:wrapper] || find_wrapper_mapping(input_type)
    name.respond_to?(:render) ? name : SimpleForm.wrapper(name)
  else
    wrapper
  end
end

def find_wrapper_mapping(input_type)

2) If not, it tries to find a config
1) It tries to find a wrapper for the current form

Attempts to find a wrapper mapping. It follows the following rules:
def find_wrapper_mapping(input_type)
  if options[:wrapper_mappings] && options[:wrapper_mappings][input_type]
    options[:wrapper_mappings][input_type]
  else
    SimpleForm.wrapper_mappings && SimpleForm.wrapper_mappings[input_type]
  end
end

def full_error(attribute_name, options = {})


f.full_error :token #=> Token is invalid

== Examples

when errors for a hidden field need to be shown.
Return the error but also considering its name. This is used
def full_error(attribute_name, options = {})
  options = options.dup
  options[:error_prefix] ||= if object.class.respond_to?(:human_attribute_name)
    object.class.human_attribute_name(attribute_name.to_s)
  else
    attribute_name.to_s.humanize
  end
  error(attribute_name, options)
end

def hint(attribute_name, options = {})


f.hint "Don't forget to accept this"
f.hint :name, id: "cool_hint"
f.hint :name # Do I18n lookup

== Examples

as :hint_html.
an attribute for I18n lookup or a string. All the given options are sent
Creates a hint tag for the given attribute. Accepts a symbol indicating
def hint(attribute_name, options = {})
  options = options.dup
  options[:hint_html] = options.except(:hint_tag, :hint)
  if attribute_name.is_a?(String)
    options[:hint] = attribute_name
    attribute_name, column, input_type = nil, nil, nil
  else
    column      = find_attribute_column(attribute_name)
    input_type  = default_input_type(attribute_name, column, options)
  end
  wrapper.find(:hint).
    render(SimpleForm::Inputs::Base.new(self, attribute_name, column, input_type, options))
end

def initialize(*) #:nodoc:

:nodoc:
def initialize(*) #:nodoc:
  super
  @object   = convert_to_model(@object)
  @defaults = options[:defaults]
  @wrapper  = SimpleForm.wrapper(options[:wrapper] || SimpleForm.default_wrapper)
end

def input(attribute_name, options = {}, &block)


given SimpleForm.time_zone_priority and SimpleForm.country_priority are used respectively.
Some inputs, as :time_zone and :country accepts a :priority option. If none is

== Priority

value_method: the method to apply on the array collection to get the value

label_method: the method to apply on the array collection to get the label

collection: use to determine the collection to generate the radio or select

inputs), you have three extra options:
When playing with collections (:radio_buttons, :check_boxes and :select

== Collection

f.input :created_at, include_blank: true

prompt and/or include blank. Such options are given in plainly:
Some inputs, as datetime, time and select allow you to give extra options, like

== Options

input html, supply :input_html instead and so on.
the label html you just need to give a hash to :label_html. To configure the
Besides the html for any component can be changed. So, if you want to change

hint: false. The same works for :error, :label and :wrapper.
So, for instance, if you need to disable :hint for a given input, you can pass
The fact SimpleForm is built in components allow the interface to be unified.

by default.
required: defines whether this attribute is required or not. True

can use it to generate a text field for a date column.
as: allows you to define the input type you want, for instance you

You have some options for the input to enable/disable some functions:

heuristic to determine which is the best option.
Each database type will render a default input, based on some mappings and

can't be blank
My hint
name="user[name]" type="text" value="Carlos" />

* Super User Name!
def input(attribute_name, options = {}, &block)
  options = @defaults.deep_dup.deep_merge(options) if @defaults
  input   = find_input(attribute_name, options, &block)
  wrapper = find_wrapper(input.input_type, options)
  wrapper.render input
end

def input_field(attribute_name, options = {})




- when the input is invalid:



- when the input is valid:

the class configured according to the validation:
When the validation happens, the input will be rendered with

end
f.input_field :name
simple_form_for @user do |f|

end
config.input_field_error_class = 'is-invalid'
config.input_field_valid_class = 'is-valid'
SimpleForm.setup do |config|
# config/initializers/simple_form.rb

It also support validation classes once it is configured.

name="user[name]" type="text" value="Carlos" />

This is the output html (only the input portion, not the form):

end
f.input_field :name
simple_form_for @user do |f|

== Examples

are sent as :input_html.
Creates a input tag for the given attribute. All the given options
def input_field(attribute_name, options = {})
  components = (wrapper.components.map(&:namespace) & ATTRIBUTE_COMPONENTS)
  options = options.dup
  options[:input_html] = options.except(:as, :boolean_style, :collection, :disabled, :label_method, :value_method, :prompt, *components)
  options = @defaults.deep_dup.deep_merge(options) if @defaults
  input      = find_input(attribute_name, options)
  wrapper    = find_wrapper(input.input_type, options)
  components = build_input_field_components(components.push(:input))
  SimpleForm::Wrappers::Root.new(components, wrapper.options.merge(wrapper: false)).render input
end

def label(attribute_name, *args)


f.label :name, id: "cool_label"
f.label :name, required: false

f.label :name, label: "Name" # Same as above, but adds required tag
f.label :name, "Name" # Same behavior as Rails, do not add required tag
f.label :name # Do I18n lookup

== Examples

as :label_html.
through the :label option or using i18n. All the given options are sent
Creates a default label tag for the given attribute. You can give a label
def label(attribute_name, *args)
  return super if args.first.is_a?(String) || block_given?
  options = args.extract_options!.dup
  options[:label_html] = options.except(:label, :label_text, :required, :as)
  column      = find_attribute_column(attribute_name)
  input_type  = default_input_type(attribute_name, column, options)
  SimpleForm::Inputs::Base.new(self, attribute_name, column, input_type, options).label
end

def lookup_action #:nodoc:

:nodoc:
The action to be used in lookup.
def lookup_action #:nodoc:
  @lookup_action ||= begin
    action = template.controller && template.controller.action_name
    return unless action
    action = action.to_s
    ACTIONS[action] || action
  end
end

def lookup_model_names #:nodoc:

:nodoc:

["route", "blocks", "blocks_learning_object", "foo"]
route[blocks_attributes][0][blocks_learning_object_attributes][1][foo_attributes]

Example:

explicit child indexes.
Extract the model names from the object_name mess, ignoring numeric and
def lookup_model_names #:nodoc:
  @lookup_model_names ||= begin
    child_index = options[:child_index]
    names = object_name.to_s.scan(/(?!\d)\w+/).flatten
    names.delete(child_index) if child_index
    names.each { |name| name.gsub!('_attributes', '') }
    names.freeze
  end
end

def mapping_override(klass)

def mapping_override(klass)
  name = klass.name
  if name =~ /^SimpleForm::Inputs/
    input_name = name.split("::").last
    attempt_mapping_with_custom_namespace(input_name) ||
      attempt_mapping(input_name, Object)
  end
end