In my application I have a Network domain class and some other domain classes that extend it - TwitterNetwork, FacebookNetwork, etc. I wanted to handle the CRUD functionality for these classes in a single controller, but keep the forms separate. Having auto-generated the controller + views and then deleted the stuff I didn't want, here's the structure I ended up with:
- grails-app
- domain
- Network.groovy
- FacebookNetwork.groovy
- TwitterNetwork.groovy
- controllers
- NetworkController.groovy
- views
- network
- list.gsp
- facebookNetwork
- create.gsp
- edit.gsp
- twitterNetwork
- create.gsp
- edit.gspOut of the box, the default list action just works:def list = {
if (!params.max) params.max = 10
[ networkInstanceList: Network.list(params) ]
}As do the delete, save and update actions.
All I have to do now is get the edit and create actions to use the correct view, depending on the network type. To do this I use the class name to determine which view to use. For example, here's my edit action:
def edit = {
def networkInstance = Network.get(params.id)
renderEditForm(networkInstance)
}
def renderEditForm(network) {
def map = [ networkInstance : network ]
def viewPath = getViewPath(network)
render(view:"/${viewPath}/edit", model:map)
}
// derive the view path from the given network instance
def getViewPath(network) {
def networkName = getName(network)
networkName[0].toLowerCase() + networkName[1..-1]
}The great thing is, I know that will work because by convention Grails will put the views for TwitterNetwork in the twitterNetwork folder and the views for FacebookNetwork in the facebookNetwork folder. It then becomes a simple case of taking the class name and making the first character lower case.
I use the same principle for my create action:
static networks = [ "twitter" : TwitterNetwork,
"facebook" : FacebookNetwork ]
def create = {
def networkInstance = createNetwork(params.type)
networkInstance.properties = params
renderCreateForm(networkInstance, params.type)
}
// create a new network instance of the given type
def createNetwork(networkType) {
if (networkType in networks.keySet()) {
def clazz = networks[networkType]
return clazz.newInstance()
}
}
... etc
And that's it! Full CRUD functionality for a set of polymorphic domain classes in a few lines of code - most of which were auto-generated by the framework. :-)

No comments:
Post a Comment