def input(method, options = {})
options[:as] ||= as(method)
options[:input] ||= {}
self.block(method, options) do
@template.content_tag(::Formula.input_tag, :class => [::Formula.input_class, options[:as]]) do
case options[:as]
when :text then text_area method, options[:input]
when :file then file_field method, options[:input]
when :string then text_field method, options[:input]
when :password then password_field method, options[:input]
when :hidden then hidden_field method, options[:input]
when :url then url_field method, options[:input]
when :email then email_field method, options[:input]
when :phone then phone_field method, options[:input]
when :number then number_field method, options[:input]
when :date then date_select method, options[:input]
when :time then time_select method, options[:input]
when :datetime then datetime_select method, options[:input]
end
end
end
end
# Generate a suitable form association for a given method by performing introspection on the type.
#
# Options:
#
# * :label - override the default label used ('Name:', 'URL:', etc.)
# * :error - override the default error used ('invalid', 'incorrect', etc.)
# * :association - add custom options to the input ({ :class => 'goregous' }, etc.)
# * :container - add custom options to the container ({ :class => 'gorgeous' }, etc.)
#
# Usage:
#
# f.association(:category, Category.all, :id, :name, :hint => "What do you do?")
# f.association(:category, Category.all, :id, :name, :association => { :prompt => "Category?" })
# f.association(:category, Category.all, :id, :name, :association => { :html => { :class => "category" } })
#
# Equivalent:
#
#
def association(method, collection, value, text, options = {})
options[:as] ||= :select
options[:association] ||= {}
options[:association][:html] ||= {}
self.block(method, options) do
@template.content_tag(::Formula.association_tag, :class => [::Formula.association_class, options[:as]]) do
case options[:as]
when :select then collection_select(:"#{method}_id", collection, value, text,
options[:association], options[:association].delete(:html))
end
end
end
end
private
# Introspection on the column to determine how to render a method. The method is used to
# identify a method type (if the method corresponds to a column)
#
# Returns:
#
# * :text - for columns of type 'text'
# * :string - for columns of type 'string'
# * :integer - for columns of type 'integer'
# * :float - for columns of type 'float'
# * :decimal - for columns of type 'decimal'
# * :datetime - for columns of type 'datetime'
# * :date - for columns of type 'date'
# * :time - for columns of type 'time'
# * nil - for unkown columns
def type(method)
column = @object.column_for_attribute(method) if @object.respond_to?(:column_for_attribute)
return column.type if column
end
# Introspection on an association to determine if a method is a file. This
# is determined by the methods ability to respond to file methods.
def file?(method)
@files ||= {}
@files[method] ||= begin
file = @object.send(method) if @object && @object.respond_to?(method)
file && ::Formula.file.any? { |method| file.respond_to?(method) }
end
end
# Introspection on the field and method to determine how to render a method. The method is
# used to generate form element types.
#
# Returns:
#
# * :url - for columns containing 'url'
# * :email - for columns containing 'email'
# * :phone - for columns containing 'phone'
# * :password - for columns containing 'password'
# * :number - for integer, float or decimal columns
# * :datetime - for datetime or timestamp columns
# * :date - for date column
# * :time - for time column
# * :text - for time column
# * :string - for all other cases
def as(method)
case method
when /url/ then return :url
when /email/ then return :email
when /phone/ then return :phone
when /password/ then return :password
end
case type(method)
when :string then return :string
when :integer then return :number
when :float then return :number
when :decimal then return :number
when :timestamp then return :datetime
when :datetime then return :datetime
when :date then return :date
when :time then return :time
when :text then return :text
end
return :file if file?(method)
return ::Formula.default_as
end
# Generate error messages by combining all errors on an object into a comma seperated string
# representation.
def error(method)
@object.errors[method].to_sentence
end
# Create an array from a string, a symbol, or an undefined value. The default is to return
# the value and assume it has already is valid.
def arrayorize(value)
case value
when nil then return []
when String then value.to_s.split
when Symbol then value.to_s.split
else value
end
end
public
# Generates a wrapper around fields_form with :builder set to FormulaFormBuilder.
#
# Supports:
#
# * f.formula_fields_for(@user.company)
# * f.fieldsula_for(@user.company)
#
# Equivalent:
#
# * f.fields_for(@user.company, :builder => Formula::FormulaFormBuilder))
#
# Usage:
#
# <% f.formula_fields_for(@user.company) do |company_f| %>
# <%= company_f.input :url %>
# <%= company_f.input :phone %>
# <% end %>
def formula_fields_for(record_or_name_or_array, *args, &block)
options = args.extract_options!
options[:builder] ||= self.class
fields_for(record_or_name_or_array, *(args << options), &block)
end
alias :fieldsula_for :formula_fields_for
end
module FormulaFormHelper
@@builder = ::Formula::FormulaFormBuilder
# Generates a wrapper around form_for with :builder set to FormulaFormBuilder.
#
# Supports:
#
# * formula_form_for(@user)
#
# Equivalent:
#
# * form_for(@user, :builder => Formula::FormulaFormBuilder))
#
# Usage:
#
# <% formula_form_for(@user) do |f| %>
# <%= f.input :email %>
# <%= f.input :password %>
# <% end %>
def formula_form_for(record_or_name_or_array, *args, &proc)
options = args.extract_options!
options[:builder] ||= @@builder
form_for(record_or_name_or_array, *(args << options), &proc)
end
alias :formula_for :formula_form_for
# Generates a wrapper around fields_for with :builder set to FormulaFormBuilder.
#
# Supports:
#
# * f.formula_fields_for(@user.company)
# * f.fieldsula_for(@user.company)
#
# Equivalent:
#
# * f.fields_for(@user.company, :builder => Formula::FormulaFormBuilder))
#
# Usage:
#
# <% f.formula_fields_for(@user.company) do |company_f| %>
# <%= company_f.input :url %>
# <%= company_f.input :phone %>
# <% end %>
def formula_fields_for(record_or_name_or_array, *args, &block)
options = args.extract_options!
options[:builder] ||= @@builder
fields_for(record_or_name_or_array, *(args << options), &block)
end
alias :fieldsula_for :formula_fields_for
end
end