Form Widget

The Form widget can help you to create/setup and validate html forms. To use it, derive your Widget from FormWidget and implement the following methods:

* form (to generate the html form)
* validate (to validate the input)
* setup (to setup initial form values)

The form will then call the method formname_submit(result) on your controller once the widget has been submitted and validation has passed. This behaviour can be changed if you overwrite the on_submit method.
Here is an example that will display a form that asks the user to enter a string twice:
# We use the markaby generator
require 'form'
require 'cuca/generator/markaby'

class FormTestWidget < FormWidget

 include Cuca::Generator::Markaby

 # validate must set @form_errors on every element it noticed an error
 def validate
    @form_errors['input2'] = "You should enter #{params['input1']}" \
                    unless params['input1'] == params['input2']
 end

 def setup
   @input1 = "Change me"
 end


 # this method will output the html form
 def form
    mab do
       # FormErrorsWidget is another widget in the cuca collection that will
       # display any form errors (setted by the validate method) nicely
       FormErrors(@form_errors)

       form(:name=>@form_name, :method=>'post') do
         table { tr { td { "Enter something"}
                      td { input(:name=>'input1', :type=>'text',:value=>@input1) }
                    }
                 tr { td { "Enter Again" }
                      td { input(:name=>'input2', :type=>'password',:value=>@input2) }
                    }
                 tr { td {}
                      # You need to name your submit button @submit_name so
                      # the Widget can identify correctly if a form was
                      # submitted
                      td { input(:type=>'submit', :name=>@submit_name) }
                    }
               }
       end #form
   end  # mab
 end

end
Our controller can be like this:
require 'cuca/generator/markaby'

class TestController < Cuca::Controller
  include Cuca::Generator::Markaby

  def test_submit(result)
    mab { "Congratulations, you typed twice: '#{result['input1']}'" }
  end


  def run
     mab { FormTest('test') }
  end

end
The output will look like:
Enter something
Enter Again

FormWidget with ActiveRecord

If you use ActiveRecord you can use ARFormWidget to create forms for a Record.
ARForm will use ActiveRecord validations and the record layout to build the form. If submitted and validated it will call formname_submit(model) on the controller. Example:

Database Table:
CREATE TABLE users (
  id serial unique,
  username varchar(256),
  account_id integer,
  agent_id integer,
  password varchar(256),
  firstname varchar(256),
  lastname varchar(256),
  created timestamp default 'now',
  enable  boolean default 't',
  user_type varchar(32)  default 'USER' CHECK
        (user_type IN ('ROOT', 'AGENT', 'USER'))
);
Our ActiveRecord Model:
class User < ActiveRecord::Base
     validates_length_of :username, :within => 3..15
     validates_uniqueness_of :username

     # force created time to be right
     def before_create
        self.created = Time.now
     end                      
end
 
Then, a "full featured" user-add controller could look like this:
 class UserAddController < ApplicationController

   def useradd_submit(user)
    user.save!
    session.flash[:message] = 'User Added'
    stop :redirect=> "user/#{user.username}/"
   end
   
 
   def run
     mab do
         # we switch off the id and created field = they will be set
         # automatically.
         h1 { "Add a new user" }
         ARForm('useradd', User.new, :disable_on_create => ['id', 'created']) 
     end
   end
 end
Your generated form will look like:

ARFormWidget with custom layout

To build your custom layout you have to derive a new class from ARForm and overwrite the form method. To display the form elements you should use the fe and fe_for methods. These methods will return the right html code for the column type and possible with the right values. Example:
class UserFormWidget < ARFormWidget

 def output(form_name, model, options = {})
   options[:disabled_on_create] = ['id', 'created']
   super(form_name, model, options)
 end

 public
 def form
   r = mabtext { FormErrors(@form_errors) }
   r << "<form action='#{@post_to}' method='POST'>\n"
   r << " <table>"
   r << " <tr><td>Username</td><td>#{fe_for('username')}</td></tr>"
   r << " <tr><td>Password</td><td>#{fe(:password, 'password')}</td></tr>"
   r << " <tr><td>Name</td><td>#{fe_for('firstname')} #{fe_for('lastname')}</td></tr>"
   r << " <tr><td>Enabled</td><td>#{fe_for('enabled')}</td></tr>"
   r << " <tr><td>Account created</td><td>#{fe_for('created')}</td></tr>"
   r << " <tr><td>Account type</td><td>#{fe_select('user_type',['USER','AGENT','ROOT'], true)}</td></tr>"
   r << " <tr><td></td><td><input type='submit' value=#{@model.new_record? ? 'Save' : 'Update'} name='#{@submit_name}'></td><tr>"
   r << "</table>\n</form>\n"
   @_content = r
 end
end    
Output of this form will look like:

ARForm for create and updates

ARForm can be used to create initial records and to update existing ones. A user edit controller that reuses the above UserForm could be like this this example:
class UsereditController < ApplicationController
  
 def user_edit_submit(model)
   model.save!
   session.flash[:message] = "User updated!"
   stop :redirect => "user/#{user.username}"
 end

 def run
   @user = User.find(params['user_id'])
   stop :error => "Unknown user" if @user.nil?
   
   mab do
     h1 { "Edit user #{@user.username}" }
     UserForm('user_edit', @user) 
   end
 end
end
...and you'll get a form with existing values ready to be updated.


<------ Back to Index