Tuesday, October 20, 2009

Session Notes - Grails Quick Start

Presenter: Dave Klein - Author of Grails Quick-Start Guide (Pragmatic Programmers)

  • groovymag - 20% off with code 2gx1
  • Sample App - Java UG Mgmt App
    • Domain model:
      • Speaker
      • Meeting
      • Sponsor
      • Member (member data already in legacy db)
  • Groovy properties
    • by declaring, they automatically have get/set methods generated
    • can override these if you need to implement something specific in get/set
    • when you access properties via dot notation, behind the scenes it's calling get/set
  • constraints
    • these determine the order in which things are listed in the list and form views
    • by default string fields get 255 varchar in the database
    • if you use a maxSize in the constraints this gives you a textarea on the edit page and a larger text data type in the db
  • toString method
    • by default this will be the class name and the ID
    • good idea to override so toString calls output something more useful
    • particularly helpful with drop-down lists since grails calls toString() on domain classes when generating drop-downs
  • custom validators
    • use groovy code to implement your own validation
    • can be inline in the constraints block or can be a separate closure
    • def meetingTimeValidator { val, obj ->
      def gc = new GregorianCalendar()
      gc.time = val
      gc.get(Calendar.HOUR) == 18 } // ensures meeting time is at 6 pm
  • unit tests
    • mockDomain() -- allows to test domain classes in an isolated manner
      • e.g. mockDomain(Meeting, []) -- this gives you an empty list and will be what's accessed in your unit tests
      • this also gives you all the dynamic methods (GORM, validate(), etc.) in your mocked domain
    • remember that stubbed out tests will pass even though you haven't implemented them, so you'll see passing tests when you run your tests even though they aren't doing anything
    • unit tests run quite a bit faster than integration tests
  • using a "real" db
    • just drop JAR for db drivers in lib directory and set the JDBC URL
    • dev, test, and production environments in DataSource config file
    • for production recommend using JNDI so you don't have to store user name and password in the config file
  • mapping to existing data
    • e.g. member table--id field is member_num; Grails by default uses "id" as the id field name
    • other fields change to all lowercase and add underscores between words, e.g. firstName becomes first_name
    • table names by default are domain name singular (e.g. member not members)
    • if all this doesn't match up, need to add a mapping block to the domain class
      • in case of Member class, id and email fields aren't named correctly, and the table name is plural
    • static mapping = {
      table 'members'
      version false // grails adds this to all your tables; used for optimistic concurrency
      id column: 'member_num'
      columns {
      email column: 'email_address'
    • can use existing Hibernate XML mapping files instead of using DSL for mapping on a class-by-class basis
    • in this case a new field was added to an existing table; grails updated the schema but didn't alter the existing fields in the table
    • basically will always add new fields and will make any other changes based on constraints if the changes are non-destructive
      • e.g. won't shorten the length of an existing field
  • init block in Bootstrap
    • great place to stick test data--generate data so it's available when the app fires up when you're using the in-memory dev db
    • can check environments in bootstrapper so it will do specific things based on the environment the app is running in
    • new in Grails 1.2 is failOnError in save method
  • generate-all command
    • can do grails generate-all "*" to generate controllers, views, and tests for all domain classes
  • grails 1.2 uses tomcat instead of jetty for servlet container
    • also in 1.2 much of what was previously built in is now plugins--1.2 start page shows installed plugins
  • using multiple datasources in a grails app
    • a bit messy--lose a lot of the GORM methods on anything other than the primary datasource
  • can combine create forms across domain classes
    • e.g. in the meeting form, can add the fields to create the speaker on the fly
    • refer to other domain class (speaker in this case) using dot notation:
      <g:textField name="speaker.firstName" value="${meetingInstance?.speaker?.firstName}" />
  • save methods in controllers
    • params is a map containing all the fields from the submitted page
    • params will map directly to domain classes in constructors
      • e.g. def meeting = new Meeting(params)
        • maps all the params by name to the Meeting domain class properties
        • if you have nested classes, e.g. speaker, sponsor, maps those as well
      • you do need to save the objects in order for the final save to work correctly
    • if you want to manually flush the hibernate session pass flush:true to the save method
    • flash scope used for storing data for the current request and the request immediately following
      • easier than using session and having to clear it out later
    • validation happens automatically when save() is called, but you can call it explicitly as well
    • controller actions are transactional by default, but you can control this explicitly as well
  • services
    • these are spring beans
    • autowired by name
      • to use, def myController
    • can inject into controllers, domain classes, taglibs
    • help keep controllers cleaner and leaner
    • not the right place for the domain logic (avoid anemic domain syndrome)
    • can create manually or use grails create-service
    • generation script by default sets all service methods to be transactional
      • if one service method calls another, it will be transactional
    • PersonService used in conjunction with Member, but there's no person class
      • works because in Groovy, don't need to use inheritance -- all by behavior
  • plugins
    • over 300 plugins available
    • 47 javascript plugins
    • 21 security plugins
    • 36 css plugins
    • easy to install -- grails install-plugin pluginName
    • http://grails.org/plugin/home
  • grails ui plugin -- based on YUI library
    • provides
      • DataTable
      • Dialog
      • Auto-Complete
      • Accordian control
      • more
    • e.g. better date picker than default drop-downs used for selecting dates
      • just replace g:datePicker with gui:datePicker in gsp pages
      • declare the tablib and the specific resources being used on each page
        • this way it only loads what you need
      • this returns the date to the controller as a string, so have to modify the controller a bit
        • params.dateTime = new Date().parse("MM/dd/yyyy hh:mm", params.dateTime)
        • default grails datepicker does this step automatically
  • url mapping
    • create more meaningful urls
    • help to hide implementation details
    • gateway to REST in grails
    • e.g. find meeting by year and month
    • update show action to support new url mapping
      • def show = {
        def meetingInstance
        if (params.year) {
        meetingInstance = findMeetingByMonthAndYear(params)
        } else {
        meetingInstances = Meeting.get(params.id)
  • gsp tags
    • build reusable components
    • get code out of the view
    • make pages more readable/maintainable
    • encapsulate domain knowledge
    • very easy to create


Anonymous said...

Hi Matthew,Is the code for doing these things in your pragmatic book on grails? I am specifically interested in can combine create forms across domain classes* e.g. in the meeting form, can add the fields to create the speaker on the fly * refer to other domain class (speaker in this case) using dot notation: <g:textfield />

Matthew Woodward said...

Hi Alfred--just so it's clear I didn't write the Grails Quick Start; Dave Klein is the author of the book. I highly, highly recommend it. It's one of the better tech books I've ever read period, and the absolute best way to dive into Grails. Graeme Rocher and Jeff Brown's "Definitive Guide to Grails" (second edition) is also fantastic.