Hi guys, this my first post in English and I decided to do this because in this way I can help more people. I’ve been working in a project that we have to develop a web application to manage licenses, to create serial numbers and to validate them. As the classes for generating and validating serial number were written in Java, we decided to develop in Grails (which is much more productive than JSP, Servlets, Struts and other stuffs like these). However (when somebody says ‘However’ or a similar adverb, watch out!
), when I started developing in Grails, I felt a bit (being euphemistic) disappointed. I’m a Rails developer, so it was natural to compare Grails with Rails. I missed lots of awesome features (like migrations, helpers, rjs, …) that Rails gives to us, programmers, when I developed in Grails for the first time. Nevertheless (watch it out!), part of that frustrating first experience with Grails was due to lack of knowledge. After studying for some days and googling a lot, I took note some tips that if had read before, I would have had a better first impression of this good framework (it is not awesome because Rails is, and Rails is much more mature and complete).
- Grails is not a Rails with Groovy: If you are a RoR programmer, keep in mind that Grails is very different of Rails. You will miss a lot of great Rails stuffs, but you can find fun stuffs on Grails also. Groovy is much more straightforward than Java (in my opinion), but that is not as productive as Ruby. So, try to forget about Rails for a while when you start programming in Grails.
- Read the Groovy Quick Start Guide: I do advise you to read the Quick Start Guide. You need only 5-10 minutes to do it. If you have a bit more time, take a look at the Getting Started Guide. It is also a guide very useful. When you need a reference, this can be helpful.
- Read the Grails User Guide: The Quick Start and User Guide will give you enough knowledge to start a Grails project.
- Take a look at Grails plugins before creating your own: There are a lot of great plugins in the Grails Plugin page. Before starting your project, take a brief look on the existing plugins and try some of them. You can also help the Grails community improving some of them.
- Install the plugin magic-numbers: If you are a Ruby programmer, probably you would like doing things like 2.days or 3.day.ago. You can do these things, only installing the magic numbers plugin. For instance, if you want to proceed only if an entry was created during the last three days, you can do the following:
if (3.days.ago.toDate() > dateCreated) { // do something }
- Unique constraint is case sensitive: This unique constraint really pissed me off. I’d like to add a unique constraint (basically a constraint is used to validate and to define the table structure) that was also case insensitive. I wouldn’t like to have two different entries whose name property were Promine and PROMINE. I thought it would be very straightforward, but it won’t. The only way I figured out to put the code to work properly was the following one:
name(blank:false, maxSize:255, validator: { val, obj -> // check if it is unique with case insensitive def app = Application.withCriteria{ ilike('name', val) if(obj.id){ ne('id', obj.id) } } return (app) ? "default.not.unique.message" : null })
I found some solutions but none of them worked properly when editing a record, since they did not check the entry id.
- Order by nested properties: If you generate a crud and change the list.gsp view including (or changing) some sortableColumns, probably you face a boring problem: sort nested properties. If you look the Sortable Column Tag page you will see a ’solution’: using criteria instead of list. Unfortunately, it doesn’t work if you want to sort by a nested property of a nested property. For instance, suppose you have these entities Application(id, name, code), ApplicationType(id, applicationId, name) and License (id, serialNumber, applicationTypeId). In the license list page, you cannot have sortable column Application Name, unless you install the GORM Labs plugin. This plugin, among other cool improvements, provides us a feature to sort by nested properties separated by dot, like order(‘applicationType.application.name’, ‘asc’). See the code below.
Controller
def list = { // sets some default values if they were not passed as argument if (!params.max) params.max = 10 if (!params.offset) params.offset = 0 if (!params.sort) params.sort = "id" if (!params.order) params.order = "asc" // gets the records via criteria in order to enable sortableColumn // for nested properties def licenseList = License.withCriteria { maxResults(params.max?.toInteger()) firstResult(params.offset?.toInteger()) // order the results using the gorm labs plugin functionality order(params.sort, params.order) } [licenseInstanceList: licenseList] }
View
<g:sortableColumn property="applicationType.application.name" title="Name" />
- Create your own tag libs: As a Rails programmer, I usually create helper methods to organize my view code and to adhere the DRY philosophy. Let’s consider that tag libs on Grails acts_as_rails_helper. You can create your own tag libs and create methods to be invoked statically from views and controllers, for instance. See below an example of a basic tag lib:
class UtilTagLib { static String cleanSerialNumber(String sn){ return (sn =~ /[^0-9A-Z]/).replaceAll("") } }
- discard() method can save your life: Grails can save an object even if you don’t have an explicit call to the method save(flush: true). Sometimes weird things happen, and when they happen, remember that there is the discard() method. According to the Grails wiki, the discard method “discards any changes that have been made during an update. Note that this method will not clean or reset the object with the original values it will just prevent it from being automatically saved by Grails.”
- Interceptors can be very useful and elegant: An interceptor is a method called before or after some pre-defined (or all) actions of a controller. If you need to execute a set of commands before some (or all) actions, don’t repeat yourself, create an interceptor. Declaring a before interceptor is very simple:
Execute before all actions
def beforeInterceptor = { // do something }
Execute before all actions, but index
def beforeInterceptor = [action:this.&setEvents, except:'index'] def setEvents() { // do something }
Execute only before save action
def beforeInterceptor = [action:this.&normalizeData, only:'save'] def normalizeData() { // do something }
Popularity: 51% [?]
Write a Comment