Sunday, September 30, 2007

Grails (0.6) Gotchas...

  • Multi-select dropdown box with size attribute doesn't work as expected

  • Though the documentation select tag in GSP tablibrary doesn't explicitely say anything about multiple select, it works by passing additional parameters ( multiple="multiple" size="4").
    e.g.

    <g:select name="stockPurchase.id" from="${StockPurchase.list()}" optionkey="id" multiple="multiple" size="4"></g:select>


    However, the result will produce a multi select drop-down but the size attribute is not honored. The bug lies in css. Open main.css under web-app/css and edit the following line and remove select,:

    input, select, textarea {


  • many-to-many stores relations in wrong columns

  • e.g.
    Problem domain
    A stock is sold that was purchased multiple times (in fractions).
    A stock is sold multiple times (in fractions) that was purchased in whole once.

    Domain Classes

    class StockPurchase {
    static belongsTo = [StockSale]
    static hasMany = [stockSales:StockSale]
    }

    class StockSale {
    static hasMany = [stockPurchases:StockPurchase]
    }

    Controller

    class StockSaleController {
    //code omitted for brevity
    //...
    def save = {
    def stockSale = new StockSale()
    stockSale.properties = params

    def stockPurchases = params.'stockPurchase.id'
    stockPurchases.each {
    stockSale.addToStockPurchases(StockPurchase.findById(it))
    }

    if(stockSale.save()) {
    flash.message = "StockSale ${stockSale.id} created."
    redirect(action:show,id:stockSale.id)
    }
    else {
    render(view:'create',model:[stockSale:stockSale])
    }
    }
    }


    In addition to stock_sale and stock_purchase tables, it also craetes a reference table named stock_sale_stock_purchase (with columns stock_sales_id, stock_purchases_id) automatically to support many-to-many relationship.

    However, when a stock sale is saved, the reference table ends up with ids switched. But the application works correctly as expected.

    I initially thought there could be a bug. But looks like there isn't and it is expected to work that way.

    Check for an explanation by Graeme Rocher here


Thursday, September 13, 2007

How to add a Usage message to maven builds

The easier way is to use the antrun plug-in's run goal, bind it to the validate phase (the first phase in the list of maven 2.0 phases), and configure the plug-in to echo the usage string.
e.g.


<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelversion>4.0.0</modelversion>
<groupid>com.giri</groupid>
<artifactid>com.giri</artifactid>
<name>UsageExample</name>
<version>1.0.0</version>
<description>
MavenUsageExample-
Usage: mvn [-Dplatform.type=local/dev/qa/stage/prod]
--platform.type is taken for resources to package.
</description>
<properties> <!-- Defaults to local. To override, define like: mvn -Dplatform.type=dev -->
<platform.type>local</platform.type>
</properties>
<build>
<defaultgoal>assembly:assembly</defaultgoal>
<sourcedirectory>src/java</sourcedirectory>
<resources> <!-- only include platform related resources -->
<resource>
<directory>
src/resource/${platform.type}
</directory>
</resource>
</resources>
...
<plugins>
...
<plugin>
<artifactid>maven-antrun-plugin</artifactid>
<executions>
<execution>
<id>echo-usage</id>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<echo>***********************</echo>
<echo>
Usage:
mvn [-Dplatform.type=local/dev/qa/stage/prod]
</echo>
<echo>
-Dplatform.type is optional.
If not specified, default is local
</echo>
<echo>***********************</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
</project>


Saturday, September 08, 2007

Fast Rail with Grails in just 2 minutes

  1. Install Groovy


  2. Install Grails


  3. Start a new Application

    • C:\grails-apps>grails create-app appname (appname is optional, if not given, it will ask anyway)
    • Check the directory appname and all sub-directories it creates under. The application is eclipse ready and ANT ready with .project and .classpath and build.xml files (it would have been more nicer if maven had been considered instead of ANT :) Hope to see MAVEN support added in coming releases).
    • Import the project into eclipse.


  4. Setup new application for MySql
    • Explode the zip and copy the jar to /lib directory under the newly created application

    • Create databases (dev, test, prod) in MySql database. E.g. gspin_dev, gspin_test and gspin_prod

    • Edit DataSource.groovy under /conf for MySql

    E.g.


    dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
    username = "root"
    password = "root"
    }
    // environment specific settings
    environments {
    development {
    dataSource {
    dbCreate = "update" // one of 'create', 'create-drop','update'
    url = "jdbc:mysql://localhost/gspin_dev"
    }
    }
    test {
    dataSource {
    dbCreate = "update"
    url = "jdbc:mysql://localhost/gspin_test"
    }
    }
    production {
    dataSource {
    dbCreate = "update"
    url = "jdbc:mysql://localhost/gspin_prod"
    }
    }
    }

    • Create a domain class (.groovy)
      E.g. User as follows

    class User {
    String userId
    String password

    static constraints = {
    userId()
    password()
    }

    String toString() { this.userId }
    }

  5. Run the application

  6. E.g.

    C:\my-grails-app\gspin>grails run-app

    • Check the gspin_dev and notice the table User created.

  7. Check the gspin_dev and notice the table User created

  8. Generate source
    • C:\my-grails-app\gspin>grails generate-all

  9. Run the application and notice that you have got nice gui for all CRUD operations of your User domain object
    • C:\my-grails-app\gspin>grails run-app

  10. Test the application