RuleBooks in ColdBox
Declare a rulebook once in config, then get a fresh copy anywhere in your app.
On this page
RuleBooks in ColdBox
In lesson 6 you wired up the action and the file by hand each time. In a real app you do that once, in config, and ask for the rulebook by name.
Declare it
Add a rulebook to your app's config/ColdBox.bx. The setting goes inside
configure():
variables.moduleSettings = {
rulebox = {
rulebooks = {
"loan" : {
"source" : "config/rules/loan.json",
"actions" : { "decide" : "DecisionAction" }
}
}
}
}
Write
variables.moduleSettings. Leaving offvariables.is a common mistake in a BoxLang config, and ColdBox then ignores the setting without any error.
source is the JSON file from lesson 6, found relative to your app root.
If the file describes the rulebook and declares its facts, they come along.
The same struct also takes description, facts, enforceFacts and
strictFacts keys, for when you would rather keep them in config.
actions maps the action name to a WireBox ID, so the code lives in a
normal class. Save this as models/DecisionAction.bx:
class {
function execute( facts, result, params ){
result.setValue( params.decision )
}
}
An action is any object with an execute( facts, result, params ) method.
Use it
Ask for the rulebook by name with the ruleBook() helper. It is available in
handlers, views and layouts. Update handlers/Loans.bx:
class {
function decide( event, rc, prc ){
var decision = ruleBook( "loan" )
.withDefaultResult( "MANUAL_REVIEW" )
.run( {
creditScore : rc.creditScore,
requestedAmount : rc.requestedAmount
} )
.getResult()
.getValue()
event.renderData( type="text", data=decision )
}
}
Values from rc are strings, and they still compare as numbers, so you do
not need to convert them.
Two other ways to get it
// Anywhere you have WireBox
getInstance( "RuleBookRegistry@rulebox" ).getRuleBook( "loan" )
// Inject a provider into a model or handler
property name="loanRules" inject="rulebook:loan";
// ...then use it:
loanRules.get().run( facts )
A fresh copy every time
Each of these gives you a new RuleBook. RuleBox keeps the recipe, not a built instance. That matters because a RuleBook holds facts and results while it runs, so a new one per request keeps requests from interfering with each other, even in a singleton.
For the injected form, remember to call .get(). What is injected is the
small provider, which builds the RuleBook when you ask.
Rule files in a folder
Any .json or .yaml file you drop in config/rulebox/ is picked up
automatically, named after the file. A file that needs no named actions can
be used with no config at all:
ruleBook( "pricing" ) // config/rulebox/pricing.json
Try it
Run your handler with creditScore=720&requestedAmount=100000 and you get
APPROVED. Try creditScore=540 for DECLINED.
Next: what happens when something breaks.