July 29, 2008

Rails To Grails Tips - Closures and Models

One frustrating thing I’ve discovered with Grails is the way data is sent to the view pages.

In Rails, it looks a little like this:

@scenario = Secenario.new
@scenario.title = "New Scenario"
@scenario.description = "Add A Description Here"

render :view => 'create'

This snippet creates a new Scenario object, populates it, and tells Rails to render the create.rhtml file, with the @scenario object in the page’s model, helpfully known as @scenario

In Grails, it looks like this:

def scenario = new Scenario()
scenario.title = "New Scenario"
scenario.description = "Add A Description Here"

render( view: create, model: [ scenario: scenario ])

and, similarly, Grails knows to render the create.gsp file, and the scenario object is available to the page as scenario

Which isn’t terribly different, and fairly easy to use.

The problem comes in because of the way Grails uses closures to provide the action methods on the controllers (edit, create, delete, save, etc).

In Grails, you might have a action method as such:

def create = {  // closure of action method here }

Now, look at the previous Grails code. Do you see the issue? Yes - create is now overloaded, and in some cases, Grails will attempt to find a page named Controller_closure_blah_blah_blah.jsp, which is obviously completely wrong.

The fix is simple:

render( view: 'create', model: [ scenario: scenario ]) 

Basically, make sure you always use quotes for your string values, even though the Groovy language allows you to leave the quotes off. Otherwise, you’ll occasionally get frustrating and confusing results.

July 24, 2008

Rails to Grails Tips - GSP tags and Array Primitives

Interesting issue that left me scratching my head this morning…

using gsp tags, you can iterate over arrays:

   <g:each in="${myarray}">
      <p>${it.title}</p>
   </g:each>

but if you do something slightly more clever:

   <g:each in="${myarray}">
      <p><g:link action='myaction' id='${it.id}'>${it.title}</g:link></p>
   </g:each>

You’ll get null pointer exceptions.

Why?

Because the <g:link> tag creates its own instance of the special variable it inside its own ‘domain’.

Fix

add the parameter var=’myvar’ to the <g:each”> tag: <g:each in=”${myarray}” var=”myvar”>. Then, use ${myvar.id} and ${myvar.title} in your code:

   <g:each in="${myarray}" var="myvar">
      <p><g:link action='myaction' id='${myvar.id}'>${myvar.title}</g:link></p>
   </g:each>

And everything should work again.

July 23, 2008

Rails to Grails Tips - Flash Messages/Errors

If you’ve used Rails, you’re familiar with the flash, and all the nifty things you can do with it.

In Grails, you have flash, but you also have an entire tag library of <g:hasError>, <g:renderErrors> and so forth. None of which, as far as I can tell, care one whit about the flash. They’re all focused on domain objects, and the errors associated with processing them.

(In my opinion, this is one of the frustrations of Grails examples - the tendency to get the domain connected to the view via scaffolding, and then the author changes the subject)

But you can use the flash, in much the same way as Rails. For example, I put the following in my top-level layout template:


              <g:if test="${flash.error}">
                 <div class="errorbox">
                    ${flash.error}
                 </div>
              </g:if>

              <g:if test="${flash.message}">
                 <div class="messagebox">
                    ${flash.message}
                 </div>
              </g:if>

(note that you’ll have to define the messagebox and errorbox css classes)

Putting information into the flash is straightforward:


     flash.error = "Your error message here."

Hope this helps!

lolcats

Can’t resist
catshrubbery.jpg

July 21, 2008

Clif Bar Triathlon Start Commercial

Heheheh

July 7, 2008

Interesting

My site was “partially” down for a week or two, because someone hacked a malware iframe into one of my posts, and Google flagged it.  This cascaded into Firefox 3 refusing to let me visit my site (bleh).  I was able to find the post, remove the offending iframe (and upgrade to the latest version of WordPress).

Still, more than a little frustrating to discover accidentally that my website was blocked.