====== The concepts : Flow ====== ===== What is a flow ===== A flow is an instance of the ActionFlow::Base class. It consists mainly of two things. * **Mapping** \\ The instructions which tell the ActionFlow framework what to do and when to do it. * **Step definitions** \\ The definition of what the declared steps do. All the flow mapping must be done in Ruby objects standard ''initialize'' method. Then, we define the step definitions, if needed. More information on [[creating controllers]] is available. ==== Mapping ==== The mapping is the first part of an ActionFlow controller. It defines the logical arrangement of [[step|steps]] and what to do when a given [[event]] or [[error]] is encountered. Here's a sample flow step mapping. action_step :init do # Tells what to do when the 'success' event is returned on :success => :display_something # Maps an error to a step call upon :SomeCustomException => :handle_custom_error end view_step :display_something do # We define what to do depending on the submit button value. # As you can see, the on method can handle a block on { :ok => :do_something, :cancel => :clean } end The code which is included in the step definitions are entirely up to the step type used. Please refer to the proper documentation. One important thing to know though is that all steps inherit from [[Flow Step]]. Therefore, all it's instructions are available to any [[step]] type. The [[Flow Step|on]] instruction tells what to do when a given [[event]] is returned, while the [[Flow Step|upon]] instruction tells what to do when a given [[error]] is rescued. In the examples above, the ''init'' [[step]] is simply redirecting to the ''display_something'' [[step]] if the success [[event]] is returned. If an [[error]] of the ''SomeCustomException'' class gets rescued by ActionFlow, the ''handle_custom_error'' [[step]] will be executed next. ==== Step Definitions ==== Once the mapping is established, you have to define the steps themselves. Defining steps is as simple as this. def init # Nothing to do, just a sample after all... # Let's just send a 'success' event. event :success end def display_something # A view step can call all the 'render' functions it wants. # It can also be a redirect, or whatever is needed--let's render. render_partial :whatever # If the step wants the framework to display the view, simply return # the 'render' Event. 'render' is a reserved event name. The framework knows # that it must now display a view. event :render end Also note that not all the steps need an explicit definition block. The [[View Step]], for example, doesn't need it. It has a default behavior and therefore knows what to render. ===== Flow instructions ===== Just like a step, some instructions tell the flow what to do on certain conditions. * **Start Step** \\ Tells the flow with what step to start with. * **End Step** \\ Tells the flow when we consider that a flow has reached an end. * **Error handling** \\ A flow can be told what to do when some errors are not handled by the steps. * **Invalid flow redirection** \\ Tells where to redirect requests which submitted invalid flow ids. ==== Start Step ==== Subclasses of ActionFlow::Base must define a start step to call upon new execution of the flow. The start step is defined as follows. start_with :init The [[step]] name passed as an argument will be called and must be defined in the controller, or else an ActionFlowError will be thrown. Of course, the obligation to define the [[step]] explicitly depends on the [[step]] type. As we said earlier, the [[View Step]] doesn't need an explicit definition block. ==== End Step ==== Subclasses of ActionFlow::Base must define which is the [[flow]] end [[step]]. After execution of this [[step]] (usually a [[view step]] which redirects), the [[flow]] data will be removed from the user session data hash. The end step is defined as follows. end_with :back_to_homepage The [[step]] name passed as an argument will be called and must be defined in the controller, or else an ActionFlowError will be thrown. Of course, the obligation to define the [[step]] explicitly depends on the [[step]] type. As we said earlier, the [[View Step]] doesn't need an explicit definition block. ==== Error handling ==== A flow can be told what to do when some errors are not handled by the steps. The ''upon'' keyword does just that. It's syntax is simple and straight forward. upon :MyErrorClass => :step_name_to_go_to Adding this snippet to the ''initialize'' method of a flow controller will tell it to route the flow to the step named ''step_name_to_go_to'' if an error of class or a subclass of ''MyErrorClass'' is raised. Note that if the error is raised from a step definition which is already handling this error class, the flow will not be asked to handle it. ==== Invalid flow redirection ==== When a request arrives to a flow controller, there are three possibilities. - No [[flow execution key]] was provided, so the flow is routed to the [[step]] indicated by the ''start_with'' instruction. - A valid [[flow execution key]] was provided, so the flow can be resumed from it's last execution [[state]]. - A [[flow execution key]] was provided, but it does not correspond to an existing flow id nor flow [[state]] In the last scenario, we have the option to redirect any such request to a specific URL. The ''redirect_invalid_flows'' does exactly that. redirect_invalid_flows :url => { :controller => :static, :action => :homepage } Adding this snippet of code to the controller ''initialize'' method will tell the controller to redirect any request which gave an invalid flow id to the ''/static/homepage'' page via an HTTP 303 error code. If you don't include this instruction in your controller mapping, it will simply render a standard Rails error page with a neat little message explaining what just happened. ~~DISCUSSION~~