I want to share with my fellow StonePath users an interesting technique, exploiting a feature on the aasm gem to gather supplemental data on a transition.
Lets start with a simple workflow pattern. We have someone responsible for data entry, and they forward it on to someone who checks the validity of the work they did. This person either validates the work and sends it on for further processing, or kicks it back for some necessary fix:
Notice how we can "kick back" from the validation step - presumably the person doing the verification has found something wrong during validation and wants the data entry person to fix it. That's all well and good, but how would you feel if you were the data entry clerk and something you thought you had already finished showed back up in your to-do list without any explanation? Obviously, we want the person doing the data validation to provide a description of the problem they have found. This is what we call "Supplemental Data Gathered on a Transition".
The complete solution to this will include several parts - including the controllers, presenting forms to users in their browser, and so on. Today we are just going to look at the first part, getting the data from the point of the event call through to a transition handler.
Sending the Data to the Transition
Lets look at the code for a typical workitem that would define that workflow:
There are two important things to notice in this code example, beyond the 'normal' stonepath/aasm stuff:
1) The kickback event defines an 'on_transition' handler - the "handle_kickback" method.
2) the definition of the handle_kickback method takes a parameter... a "reason" for the kickback.
This sets up an interesting capability of aasm - the ability to pass parameters to events. Follow along with these code snippets:
>> workitem = YourTypicalWorkitem.create #creates a workitem
>> # do data entry stuff here
>> workitem.validate_data!
>> # data looks good, so...
>> workitem.approve!
No surprises there. Lets see how this works with the kickback:
>> workitem = YourTypicalWorkitem.create #creates a workitem
>> # do data entry stuff here
>> workitem.validate_data!
>> # data looks good, so...
>> workitem.kickback!
ArgumentError: wrong number of arguments (0 for 1)
The problem here is that our 'handle_kickback' is being called, and it expects a parameter... but nothing is being passed in. We need to fix that.
>> workitem = YourTypicalWorkitem.create #creates a workitem
>> # do data entry stuff here
>> workitem.validate_data!
>> # data looks good, so...
>> workitem.kickback!(nil, "You misspelled the applicant's name")
Reason Provided: You misspelled the applicant's name
Several small things to notice:
First, notice that we passed in a string, "you misspelled the applicant's name", when we performed the kickback! event.
Second, notice we also pass in a nil... I'll explain that in a future blog post - in short, it is an undocumented feature in AASM where we can choose different transitions we might want to perform. Since we aren't using that, we just pass in nil.
Finally, You can see that our string was passed to our method and output on the console thanks to the 'puts' line in the 'handle_kickback' method. In reality, we'd want this method to do something else with the data, but this proves we can get to it. We can pass data from an event into our event handler! Pretty cool.
So how does this relate to StonePath?
It is a pretty common action in StonePath to automatically create a task when entering a new state - and in this situation, we need to pass in 'handling instructions' for that task. This is exactly what this technique is used for in the NorthHarbor StonePath example, when we are closing out the lawyer review state. How that relates to the events_controller and its ability to collect that information will be the subject of a future blog post.
Lets start with a simple workflow pattern. We have someone responsible for data entry, and they forward it on to someone who checks the validity of the work they did. This person either validates the work and sends it on for further processing, or kicks it back for some necessary fix:
Notice how we can "kick back" from the validation step - presumably the person doing the verification has found something wrong during validation and wants the data entry person to fix it. That's all well and good, but how would you feel if you were the data entry clerk and something you thought you had already finished showed back up in your to-do list without any explanation? Obviously, we want the person doing the data validation to provide a description of the problem they have found. This is what we call "Supplemental Data Gathered on a Transition".
The complete solution to this will include several parts - including the controllers, presenting forms to users in their browser, and so on. Today we are just going to look at the first part, getting the data from the point of the event call through to a transition handler.
Sending the Data to the Transition
Lets look at the code for a typical workitem that would define that workflow:
There are two important things to notice in this code example, beyond the 'normal' stonepath/aasm stuff:
1) The kickback event defines an 'on_transition' handler - the "handle_kickback" method.
2) the definition of the handle_kickback method takes a parameter... a "reason" for the kickback.
This sets up an interesting capability of aasm - the ability to pass parameters to events. Follow along with these code snippets:
>> workitem = YourTypicalWorkitem.create #creates a workitem
>> # do data entry stuff here
>> workitem.validate_data!
>> # data looks good, so...
>> workitem.approve!
No surprises there. Lets see how this works with the kickback:
>> workitem = YourTypicalWorkitem.create #creates a workitem
>> # do data entry stuff here
>> workitem.validate_data!
>> # data looks good, so...
>> workitem.kickback!
ArgumentError: wrong number of arguments (0 for 1)
The problem here is that our 'handle_kickback' is being called, and it expects a parameter... but nothing is being passed in. We need to fix that.
>> workitem = YourTypicalWorkitem.create #creates a workitem
>> # do data entry stuff here
>> workitem.validate_data!
>> # data looks good, so...
>> workitem.kickback!(nil, "You misspelled the applicant's name")
Reason Provided: You misspelled the applicant's name
Several small things to notice:
First, notice that we passed in a string, "you misspelled the applicant's name", when we performed the kickback! event.
Second, notice we also pass in a nil... I'll explain that in a future blog post - in short, it is an undocumented feature in AASM where we can choose different transitions we might want to perform. Since we aren't using that, we just pass in nil.
Finally, You can see that our string was passed to our method and output on the console thanks to the 'puts' line in the 'handle_kickback' method. In reality, we'd want this method to do something else with the data, but this proves we can get to it. We can pass data from an event into our event handler! Pretty cool.
So how does this relate to StonePath?
It is a pretty common action in StonePath to automatically create a task when entering a new state - and in this situation, we need to pass in 'handling instructions' for that task. This is exactly what this technique is used for in the NorthHarbor StonePath example, when we are closing out the lawyer review state. How that relates to the events_controller and its ability to collect that information will be the subject of a future blog post.
Comments