Posts Tagged ‘form’

A stateful form

Saturday, April 26th, 2008

You probably want some interaction in your application. BTW, that’s what makes a piece of software to an application. Let’s learn how forms are handled in Apotomo. To implement this typical workflow we write a form widget.

app/cells/simple_form_cell.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class SimpleFormCell < Apotomo::StatefulWidget
 
  def transition_map
    { :form           => [:_process_form],
      :_process_form  => [:_process_form],
    }
  end
 
  def form
    @user = User.new
    nil
  end
 
  def _process_form
    res = @user.update_attributes(param(:user))
    return state_view :form unless res
 
    state_view :user_created
  end
 
end

The form widget is hooked into the application as usual.

app/apotomo/application_widget_tree.rb

def draw(root)
  # ...
  root <<  cell(:simple_form, :form, 'my_simple_form')
end

We advise the widget to invoke its state form when it’s rendered. Let’s go stepwise through this invocation:

1. Apotomo executes the method form, where we create a new User object (line 10).

2. The associated view form is rendered.

app/cells/simple_form/form.html.erb

1
2
3
4
5
6
<%= error_messages_for 'user' %>
 
<%= form_to_event(:state => :_process_form) %>
  Username: <%= text_field 'user', 'username', :size => 9 %>
  Email:    <%= text_field 'user', 'email', :size => 9 %>
<input type="submit" />

That’s a common template known from many many other rails apps.
But wait- line 3 has a method call form_to_widget spitting out a form tag.

3. The sole argument is a hash, containing the assignment :state => :_process_form. When sent, it advises the Apotomo event dispatcher to invoke the state _process_form on our form widget.

4. The second argument for form_to_widget is usually the target widget where we want to send the form input. Here, we omit it, meaning we want to address the current widget (which is, of course, my_simple_form).

In other words, if the form is submitted by the user, our form widget goes from state form into _process_form. This state checks the input and either returns the form again (line 16), with error messages, or returns another view stating success (line 18).


What about those states?

Keep in mind that we’re stateful, so you don’t have to worry about restoring the environment between the requests. This rocks. We neither have to care about restoring the User object in _process_form (line 15 - look, it’s simply already there), nor do we have to worry about where our new state views are sent to and what part of the page they update. This is all done by the StatefulWidget!

Also note that the widget automatically goes to the correct state (line 3-6). When leaving form it stays in the state _process_form. A look at the state chart makes it clear: