register
other register

Tuesday, January 20, 2009

Remote Deploy Grails Application


Ant 1.6 or later support scp, ssh tasks.

Download the lastest ant.
Set ANT_HOME variable.
Add %ANT_HOME%\bin in the PATH variable (in Windows environment).

Download the JSch jar to the %ANT_HOME%\lib

Add the remote task in the build.xml in the Grails project:

<target name="remoteDeploy" depends="war" description="-->Deploy the war to the remote server">
<scp file="LockerJet.war" trust="yes" todir="username:password@remotehost:/PATH_TO_TOMCAT/webapps"/>
</target>

Note: set trust="yes", otherwise it will thrown "reject HostKey" or "java.net.UnknownHostException"

Run the task by:

ant remoteDeploy

===============

There is another Grails remote deploy using GANT post for reference.

Friday, January 16, 2009

Clear Flash Message in Grails

According to the Grails documentation:

"Flash is a temporary storage map that stores objects within the session for the next request and the next request only, automatically clearing our the objects held there after the next request completes.

The flash object is essentially a map (a hash) which you can use to store key value pairs. These values are transparently stored inside the session and then cleared at the end of the next request.

This pattern allows you to use HTTP redirects (which is useful for redirect after post and retain values that can retrieved from the flash object."

But just in case the flash message isn't cleared for some unknow reason, there is the code to rescue in your controller:

flash.clear()

Thursday, January 15, 2009

Command Object and Error Messages

"Grails command Objects provide a simple mechanism to validate from fields that do not map directly to domain objects. "

Command Object

class JetCommand {
  String number
  String name
 
  static constraints = {
    number(blank: false, nullable: false, matches: "\\d+")
    name(nullable: false)
  }
}

The command object class may be defined under src/groovy/ or under grails-app/controllers/. The command object class may also be defined in the same source file as the controller that uses it.

If a custom error message is preferred, then look at the corresponding error code for the above constraints. Add custom error messages in the grails-app/i18n/messages.properties file:

jetCommand.number.blank=The number can't be blank
jetCommand.number.matches.invalid=The number can only be digital numbers
jetCommand.name.nullable=The name can't be null


Controller:

class JetController {
  def jet = { JetCommand cmd ->
  if (cmd.hasErrors()) {
    cmd.errors.allErrors.each {
    println it
  }
}

// You don't have to do the following code, because the Grails will handle it for you.
// If you do the following code, there will be duplicate error messages 

/**
if (cmd.errors.hasFieldErrors("name")) { 
cmd.errors.rejectValue('choice', 'searchCommand.name.nullable') 
}
         if (cmd.errors.hasFieldErrors("number")) {
                 if (cmd.errors.getFieldValue("number").isEmpty()) {
                     cmd.errors.rejectValue('number', 'searchCommand.number.blank')
                 }
                 else {
                     cmd.errors.rejectValue('number', 'searchCommand.number.matches.invalid')
                 }
             }
**/
render (view: 'admin', model:[jetCommand: cmd, key1: object1, key2: object2])
}
}
}


GSP page

You can display the error messages in the GSP page:


  


Customised Validator:

You can also add a customised validator:

static constraints = {
  number(validator: {
    if (it.isEmpty() || it == null || !(it ==~ /\d+/)) {
      return ['numberJet']  // numberJet is the error code
    }
  })
}

In this case, in the messages.properties, you should add a error message with the error code:

jetCommand.number.numberJet=Number field is not valid

Wednesday, January 14, 2009

Redirect Params in Grails

Grails params contain controller, action, and other parameters like below:

["_action_search":"Search", "choice":"Locker Register", "action":"search", "numb
er":"1", "controller":"lockerRegister"]

So when doing redirect with all the params like below:

class JetController {

def search = {

redirect (action: "jetAction", params: params)
}

def jetAction { 
// some code here
}
}

It might be in a endless redirect loop. A workaround is to manually specify the parameters your want to redirect. For example: 

redirect (action: "testAction", controller: "testController", params:[p1: 'value1', p2: 'value2']) 

Put Multiple Objects in the Returning Model in The Controller

In controller, you can put multiple objects in a model and return it. You can also pass on the parameters from the request to the model on returning it. For example:

class JetController {

def test = {
return ['key1': object1, 'key2': object2, 'key3': params.person.id]
}
}

Restart the Application After Changing the Dynamic Finders in Grails

When changing the dynamic finders (i.e. find, findAll, findBy) while the grails application is running, you need to restart the application to reflect the changes for the queries. 

If you set  "logSql=true" in your conf/DataSource.groovy, then you can monitor whether  sql queries reflect your changes.