class SimpleForm::FormBuilder

def self.discovery_cache

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

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


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] ||= reflection.klass.all(reflection.options.slice(:conditions, :order))
  attribute = case reflection.macro
    when :belongs_to
      (reflection.respond_to?(:options) && reflection.options[:foreign_key]) || :"#{reflection.name}_id"
    when :has_one
      raise ":has_one associations are not supported by f.association"
    else
      if options[:as] == :select
        html_options = options[:input_html] ||= {}
        html_options[:size]   ||= 5
        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
  input(attribute, options.merge(:reflection => reflection))
end

def attempt_mapping(mapping, at) #:nodoc:

:nodoc:
def attempt_mapping(mapping, at) #:nodoc:
  return if SimpleForm.inputs_discovery == false && at == Object
  begin
    at.const_get(mapping)
  rescue NameError => e
    e.message =~ /#{mapping}$/ ? nil : raise
  end
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 default_input_type(attribute_name, column, options) #:nodoc:

:nodoc:
collection is given.
default alwayls 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) #:nodoc:
  return options[:as].to_sym if options[:as]
  return :select             if options[:collection]
  custom_type = find_custom_type(attribute_name.to_s) and return custom_type
  input_type = column.try(:type)
  case input_type
  when :timestamp
    :datetime
  when :string, nil
    case attribute_name.to_s
    when /password/  then :password
    when /time_zone/ then :time_zone
    when /country/   then :country
    when /email/     then :email
    when /phone/     then :tel
    when /url/       then :url
    else
      file_method?(attribute_name) ? :file : (input_type || :string)
    end
  else
    input_type
  end
end

def discovery_cache #:nodoc:

:nodoc:
between requests, otherwise use the instance one.
If cache_discovery is enabled, use the class level cache that persists
def discovery_cache #:nodoc:
  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 file_method?(attribute_name) #:nodoc:

:nodoc:
def file_method?(attribute_name) #:nodoc:
  file = @object.send(attribute_name) if @object.respond_to?(attribute_name)
  file && SimpleForm.file_methods.any? { |m| file.respond_to?(m) }
end

def find_association_reflection(association) #:nodoc:

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

def find_attribute_column(attribute_name) #:nodoc:

:nodoc:
def find_attribute_column(attribute_name) #:nodoc:
  if @object.respond_to?(:column_for_attribute)
    @object.column_for_attribute(attribute_name)
  end
end

def find_custom_type(attribute_name) #:nodoc:

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

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

:nodoc:
Find an input based on the attribute name.
def find_input(attribute_name, options={}, &block) #:nodoc:
  column     = find_attribute_column(attribute_name)
  input_type = default_input_type(attribute_name, column, options)
  if input_type == :radio
    SimpleForm.deprecation_warn "Using `:as => :radio` as input type is " \
      "deprecated, please change it to `:as => :radio_buttons`."
    input_type = :radio_buttons
  end
  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) #:nodoc:

:nodoc:
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) #:nodoc:
  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(camelized, Object) || attempt_mapping(camelized, self.class) ||
        raise("No input found for #{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
  @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 respectivelly.
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]" size="100" type="text" value="Carlos" />

* Super User Name!
def input(attribute_name, options={}, &block)
  options = @defaults.deep_dup.deep_merge(options) if @defaults
  chosen =
    if name = options[:wrapper]
      name.respond_to?(:render) ? name : SimpleForm.wrapper(name)
    else
      wrapper
    end
  chosen.render find_input(attribute_name, options, &block)
end

def input_field(attribute_name, options={})


name="user[name]" size="100" 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={})
  options = options.dup
  options[:input_html] = options.except(:as, :collection, :label_method, :value_method)
  SimpleForm::Wrappers::Root.new([:input], :wrapper => false).render find_input(attribute_name, options)
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, :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

The action to be used in lookup.
def lookup_action
  @lookup_action ||= begin
    action = template.controller.action_name
    return unless action
    action = action.to_sym
    ACTIONS[action] || action
  end
end

def lookup_model_names


["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
  @lookup_model_names ||= begin
    child_index = options[:child_index]
    names = object_name.to_s.scan(/([a-zA-Z_]+)/).flatten
    names.delete(child_index) if child_index
    names.each { |name| name.gsub!('_attributes', '') }
    names.freeze
  end
end

def mapping_override(klass) #:nodoc:

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