ActiveForm provides a DSL for defining complete XHTML forms with validation. You can compose your own widgets and (nested) form sections from basic elements. Markup is generated by Builder, using several wrappers and callbacks which render their child elements accordingly. This allows one to customize all output.

Both serverside as well as clientside validation is supported and values are bound in a nested fashion to their elements, similar to how Rails expects params from forms.

It’s possible to output elements, sections and the complete forms, allowing easy integration with ERB templates. While it’s distributed as a gem it can easily be used as a plugin for Rails.

example: how to create a contact form in Rails

documentation: autogenerated rdocs

see rubyforge.org for more information. install as a gem: sudo gem install active_form

# sample001.html: compose a new form from scratch - see also: sample002.html sample003.html

form = ActiveForm::compose :myform, :client_side => true do |f|
  f.section :person, :label => 'Your details' do |s|
    s.text_element :first_name,   :required => true
    s.text_element :last_name,    :required => true
    s.password_element :password, :required => true
    s.password_element :password_confirm, :required => true
    s.select_element :country do |e|
      e.empty = 'choose a country:'
      e.options = [['Nederland', 'nl'], ['Belgiƫ', 'be']]   
      e.element_wrapper = side_by_side_wrap
    end
    s.submit_element, :label => 'Send', :element_wrapper => no_label_wrap    
    s.after_validation do |elem|
      elem.remove_element :password_confirm if elem.valid?
    end
  end
  f.section :message, :label => 'Your message' do |s|
    s.text_element :subject, :required => true, :element_wrapper => side_by_side_wrap
    s.textarea_element :message, :required => true, :rows => 5, :cols => 10 do |e|
      e.after_validation do |elem|
        elem.frozen_value = elem.formatted_value.word_truncate(32) if elem.valid?
      end
    end
    s.submit_element, :label => 'Send', :element_wrapper => no_label_wrap   
  end    
  f.after_validation do |elem|
    if elem.valid?
      remove_elements_of_type :submit, :button
      elem.freeze!
    else
      elem.css_style << 'border: 1px solid red'
    end
  end
end

# plain_view.html: create a form definition and use the plain view renderer

ActiveForm::Definition.create :sample do |f|
  
  f.client_side = true  
  
  f.section :person, :label => 'Your details' do |s|
    s.text_element :first_name,   :required => true
    s.text_element :last_name,    :required => true
    s.password_element :password, :required => true
    s.password_element :password_confirm, :required => true
    s.select_element :country do |e|
      e.empty = 'choose a country:'
      e.options = [['Nederland', 'nl'], ['Belgiƫ', 'be']]
    end
    s.submit_element :label => 'Send'  
    s.after_validation do |elem|
      elem.remove_element :password_confirm if elem.valid?
    end
  end
  
  f.section :message, :label => 'Your message' do |s|
    s.text_element :subject, :required => true
    s.textarea_element :message, :required => true, :rows => 5, :cols => 10
    s.submit_element :label => 'Send'  
  end    
  
  f.after_validation do |elem|
    if elem.valid?
      remove_elements_of_type :submit, :button
      elem.disabled = true
    end
  end
  
end

form = ActiveForm::Definition.build :sample, :my_form, :label => 'Plain View Sample'

# example of Rails integration; shown as unit test (currently more than 420 tests and 1900 assertions)

form = ActiveForm::Model::build(Book.new)
assert_kind_of ActiveForm::Definition, form
form.submit_element

names = form.collect(&:name)
assert_equal [:id, :title, :isbn, :publication_date, :publisher_id, :created_at, :updated_at, :submit], names
labels = form.collect(&:label)
assert_equal ["Id", "Title", "Isbn", "Publication date", "Publisher", "Created at", "Updated at", "Submit"], labels
types = form.collect(&:element_type)
assert_equal [:hidden, :text, :text, :select_date, :select_from_model, :select_datetime, :select_datetime, :submit], types
type_casting = form.collect(&:type_cast)
assert_equal [:integer, :string, :string, :date, :integer, :time, :time, nil], type_casting


# ActiveForm Copyright (c) 2007-2008 atelierfabien - loobmedia
# released under MIT license