Grails datePicker magic

Been working much more on the frontend side of web development lately, but found a nice trick in Grails that seemed good to throw out there.

Maybe this is documented somewhere and I just always missed it. I knew the datePicker tag in gsp’s worked nicely for binding to domainClass objects through dataBinding, but didn’t know it could also be used as a super convenient way to get a date object in a controller. This is in grails 2.3 line BTW.

Example:

My use case was a simple report that needed to be run for a given month.

in the gsp:

	
		
		
	

Sweet. That is a really quick way to generate the HTML I want.

Now, here is the really slick part I didn’t know about. In the controller I can access the params.report object and it will be a Date!

def report() {
	def forwardMonth = params.report.toCalendar()
	forwardMonth.roll(Calendar.MONTH, 1)
	forwardMonth  = forwardMonth.getTime()
	flash.message = "${params.report.toString()} -- ${forwardMonth.toString()}"
	...

Flattr this!

Grails and Spine.js decoupled development setup

Using Grails as the API server for a spine app and Spine.js as a front end framework has been going well. My Spine app has up till now lived in the web-apps directory of my Grails app. After living with this arrangement for a while I started to realize how separating the two even further would have many all-around advantages. Decoupling code makes new projects easier to manage by isolating versioning, testing, deployment/release for example.

In production environments this sort of setup isn’t all that uncommon, you let Apache or something like it serve static image, js or css files and use mod_jk or some proxy setup to pass the rest on to Java app server like Tomcat.

My setup is a little different in that I want to serve html and js and have to make sure all relative links still work for ajax API requests, and locally there is a cross domain issue if you try to simply work from files in the browser and make calls to Grails running on Tomcat

Long story short; to get my decoupled dev setup here is what I did:

  1. Install Apache
  2. Get it running
  3. Set up virtualhost that will proxy appropriate requests to Grails (need mod_proxy_http)
  4. Add alias definitions for Spine apps

Steps one and two are relatively standard stuff. On Ubuntu it is trivially easy. (sudo apt-get install apache2)

Step 3 was new to me. Searching turned up a good starting point on that, but simply proxy isn’t what I really needed. That brings us to step 4. I needed some interceptors (Alias’) for my spine apps, so that relative links still played nice. For example, I wanted ‘http://localhost/grailsApp/spineApp/’ to direct to my Spine app, while links within the spine app like ‘../api/book/5’ were handled by Grails. an old forum post contained the nugget I was looking for.

Basicially this is what I needed inside of my virtualhost block:

ProxyPass /grailsApp/spineApp !
Alias /grailsApp/spineApp /path/to/spineApp/on/fileSystem

ProxyRequests Off
ProxyPreserveHost On

ProxyPass /grailsApp http://127.0.0.1:8080/grailsApp
ProxyPassReverse /grailsAPp http://127.0.0.1:8080/grailsApp

Grails config will have to change to handle redirects and such in grails controllers, that setting is normally in grails-app/conf/Config.groovy

environments {
development {
grails.serverURL = "http://localhost/grailsApp"
...

Flattr this!

Customized Grails Controller for REST

Update: new code https://gist.github.com/4152409

Grails can do RESTfull easily enough, but I wanted a restful API from grails without throwing out grails scaffolding, So I decided to customize Grails’ controller template.

grails install-templates

then in [app-name]/src/templates/scaffolding/Controller.groovy

import org.springframework.dao.DataIntegrityViolationException
import grails.converters.XML
import grails.converters.JSON

class ${className}Controller {

	static allowedMethods = [list:'GET',
		show:'GET',
		edit:['GET', 'POST'],
		save:'POST',
		update:['POST','PUT'],
		delete:['POST','DELETE']
	]

	def index() {
		redirect(action: "list", params: params)
	}

	def list() {
		params.max = Math.min(params.max ? params.int('max') : 50, 200)
		def list = ${className}.list(params)
		def listObject = [${propertyName}List: list, ${propertyName}Total: ${className}.count()]
		withFormat {
			html listObject
			json { render list as JSON }
			xml { render listObject as XML }
		}
	}

	def create() {
		[${propertyName}: new ${className}(params)]
	}

	def save() {
		def ${propertyName} = new ${className}(params)
		if (!${propertyName}.save(flush: true)) {
			withFormat {
				html {render(view: "create", model: [${propertyName}: ${propertyName}])}
				json {
					response.status = 403
					render ${propertyName}.errors as JSON
				}
				xml {
					response.status =403
					render ${propertyName}.errors as XML
				}
			}
			return
		}
		flash.message = message(code: 'default.created.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
		withFormat {
			html {
				redirect(action: "show", id: ${propertyName}.id)
			}
			json {
				response.status = 201
				render ${propertyName} as JSON
			}
			xml {
				response.status = 201
				render ${propertyName}.id
			}
		}
	}

	def show() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}
		def object = [${propertyName}: ${propertyName}]
		withFormat {
			html {object}
			json { render object as JSON }
			xml { render object as XML }
		}
	}

	def edit() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
			redirect(action: "list")
			return
		}
		[${propertyName}: ${propertyName}]
	}

	def update() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action:"list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}

		if (params.version) {
			def version = params.version.toLong()
			if (${propertyName}.version > version) {
				${propertyName}.errors.rejectValue("version", "default.optimistic.locking.failure",
						  [message(code: '${domainClass.propertyName}.label', default: '${className}')] as Object[],
						  "Another user has updated this ${className} while you were editing")
				withFormat {
					html {render(view: "edit", model: [${propertyName}: ${propertyName}])}
					json { response.sendError(409) }
					xml { response.sendError(409) }
				}
				return
			}
		}

		${propertyName}.properties = params

		if (!${propertyName}.save(flush: true)) {
			withFormat {
				html {render(view: "edit", model: [${propertyName}: ${propertyName}])}
				json {
					response.status = 403
					render ${propertyName}.errors as JSON
				}
				xml {
					response.status = 403
					render ${propertyName}.errors as XML
				}
			}
			return
		}
		withFormat {
			html {
				flash.message = message(code: 'default.updated.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
				redirect(action: "show", id: ${propertyName}.id)
			}
			json {
				response.status = 204
				render ${propertyName} as JSON
			}
			xml {
				response.status = 204
				render ''
			}
		}
	}

	def delete() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}
		try {
			${propertyName}.delete(flush: true)
			withFormat {
				html {
					flash.message = message(code: 'default.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json {
					response.status = 204
					render ''
				}
				xml {
					response.status = 204
					render ''
				}
			}
		}
		catch (DataIntegrityViolationException e) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "show", id: params.id)
				}
				json { response.sendError(500) }
				xml { response.sendError(500) }
			}
		}
	}

}

then modify your UrlMappings.groovy file to look something like this:

class UrlMappings {

	static mappings = {
		"/$controller/$action?/$id?"{
			constraints {
			// apply constraints here
			}
		}
		name api0: "/api/$controller/$id"(parseRequest:true){
			action = [GET: "show", PUT: "update", DELETE: "delete"]
			constraints {
				id(matches:/\d+/)
			}
		}

		name api1: "/api/$controller"(parseRequest:true){
			action = [GET: "list", POST: "save"]
		}
	}
}

I found the JSON Restful plugin a while after I already did most of this, so that is another way to go. Other than it having some issues in grails 2 right now it looks like a really good option, but one thing I like about my approach is that if you want to customize your API in fine detail you can do so. You can always generate individual controllers and modify them of course. Another option is registering custom marshallers. The simple example for customizing your JSON output without changing any controller code would be doing something like this in your Bootstrap.groovy

import grails.converters.JSON
class BootStrap {
  def init = {servletContext ->;
    JSON.registerObjectMarshaller(Person) {
      def returnArray = [:]
      returnArray['name'] = it.name
      returnArray['addrs'] = it.addresses
      return returnArray
    }
    ...
  }

...

Flattr this!

Grails active page navigation menu

A Common feature found in many CMS’s or web-apps is a navigation menu with a highlighted active page, or the parent of the current page in a hierarchy. The trick is getting the proper element with an added CSS class of ‘selected’ or ‘active’. There are a number of ways to do this, but I just found a new way to do it in Grails using a Sitemesh’s pageProperty.

In my main layout gsp I have the nav menu

 
  

then in the head section of a view gsp’s where I want the appropriate element to have a ‘selected’ or ‘active’ class. I include:

    

Then in the css have something to deal with the applied class:

  #mainMenu li > a.selected { .... }

Pretty simple! I don’t know if this is very efficient in terms of performance. I can think of other ways to do this with Javascript, or params passed from the controller, but I wanted to find something that used Sitemesh as that seemed like the component that ought to handle this sort of feature. So while this is working for me, and gives a pretty good level of control, I am still wondering if it is really the ‘right’ way to do it.

For a more comprehensive explanation of Sitemesh in Grails visit this blog.

Flattr this!