Saturday, January 3, 2009

Transient properties in a domain class

It is always a common problem to create display values for a view from persistent data. Database amounts don’t have a $ sign and are not formatted, or phone numbers, dates etc. This format conversion can be done in the view with specific tags like g:formatDate or g:formatNumber, or by an own developed tag.

But if there is a specific logic to create a display value this could be done directly in the domain class with a transient variable and the related method.

class Address implements Serializable {

String acctAddr1
String acctAddr2
String acctAddr3

ZipCode zipCode

static transients = ['cityState']

static constraints = {
acctAddr1(nullable:true, blank:true, maxSize:30)
acctAddr2(nullable:true, blank:true, maxSize:30)
acctAddr3(nullable:true, blank:true, maxSize:30)
zipCode(nullable:true)
}

String getCityState() {
if ( zipCode ) {
return zipCode.city + "," + zipCode.state + " " + zipCode.zipCode
else
return ""
}
}
}

class ZipCode implements Serializable {

String zipCode
String state
String city

static constraints = {
zipCode(nullable:false, maxSize:10)
state(nullable:false, maxSize:2)
city(nullable:false, maxSize:30)
}
}

Thursday, January 1, 2009

View event (request) handling and controller design

The default Grails CRUD application consists of one controller (responsible for requests) and four pages (views). These are list, create, edit, show pages. A new controller instance is created for each request. The request can handle in different ways:

  • Call a view (page)
  • Interaction with a domain, service, get data for passing it to a view or from a view (page)
  • Writing directly to the response writer
  • Redirecting to another action in the same controller or to another controller

If no action is specified by calling a controller (e.g. URI) the controller handles a default action.

  • If the controller defines only one action, it becomes the default action.
  • A action called index, becomes the default action.def index = { redirect(action:list) }
  • A value of a defined string property called defaultAction.def defaultAction = ‘list’

A CRUD controller has the actions: index (default action), list (show list of entries), create (render create view from list), save (save new domain from create view), edit (render edit view from list), update (update existing domain from edit view), delete (delete domain from list view), show (render show view from list).

Beyond CRUD applications the page flow (views) and event (request) handling becomes more complex and complicated. Even for CRUD applications, I am wondering why we need 3 views for create, edit and show.

Controller design considerations:

Assuming a number of views in a flow to collect data where at the end follows an action (for e.g. save).

  1. One controller for one view.
  2. One controller for all views with action, redirect etc.
  3. One controller for all views with a web flow http://grails.org/WebFlow.

I suggest the third solution, even if I have good experience with solution 1. The advantage I see is the maintenance, that all requests are covered in one controller which belongs to this view flow. The grails web flow has 5 different scope you can utilize:

  • request - Stores an object for the scope of the current request
  • flash - Stores the object for the current and next request only
  • flow - Stores objects for the scope of the flow, removing them when the flow reaches an end state
  • conversation - Stores objects for the scope of the conversation including the root flow and nested subflows
  • session - Stores objects inside the users session

See example on the Web Page http://www.hbbaeuerle.com/html/controller.html