Grails: Simple locale/language selector

How you can change locales in Grails is described in the Reference Documentation. Normally you want to do this in form of a language selector. Here’s an example taglib how you can do that:

import org.springframework.web.servlet.support.RequestContextUtils;
import groovy.xml.MarkupBuilder;

class LocaleTagLib {
	static namespace = 'locale'
	
	List<Locale> locales = [Locale.GERMAN, Locale.ENGLISH]

	/**
	 * Renders a locale selector. 
	 * Adds the class <code>active</code> to the list-element of the current language. 	
	 */
	def selector = {
		Locale requestLocale = RequestContextUtils.getLocale(request)
		
		MarkupBuilder mb = new MarkupBuilder(out)
		mb.ul('id': 'locale-selector') {
			locales.each { Locale locale ->
				li(requestLocale.language == locale.language ? ['class': 'active'] : [:]) {
					mb.yield(
						link( controller: controllerName, action: actionName, params: params + [lang: locale.language], 
							 { locale.getDisplayLanguage(locale) } ).toString(),
						false 
						)
				}
			}
		}
	}
}

What you probably have to change is the collection of locales. You don’t have to provide messages for the locales, the getDisplayLanguage()-method of Locale provides the translation.

Usage:

<locale:selector />

.

Posted in Grails. Tags: , . 3 Comments »

Grails: Set sitemesh layout depending on request parameter

For Fancyboxes/Lightboxes you may want to reuse your existing views with just another layout. In the Reference Documentation you’ll find some methods to trigger the layout in a static manner.
If you want to do this dependening on a request parameter (for example layout=embedded) you have two possibilities:

1. Use a expression in the meta tag

<head>
    <meta name="layout" content="${params.layout ?: 'main'}">
...

With this approach you have to use the meta tag in your views and use the expression in every view where you want the layout to be changeable.

2. Define a filter

import org.codehaus.groovy.grails.web.sitemesh.GroovyPageLayoutFinder

/**
 * Set layout depending on request parameter. This layout has the highest priority.
 */
class LayoutFilters {
    def filters = {
        all(controller:'*', action:'*') {
            before = {
				if (params.layout) {
					request[GroovyPageLayoutFinder.LAYOUT_ATTRIBUTE] = params.layout
				}
            }
        }
    }
}

With this filter you have the ability to change the layout for every view in your application. If you only want this mechanism for some controller/actions, change the filter expression (see Applying Filters).

Grails Fields Plugin: select with internationalized labels

If you are using the Fields Plugin and want to have a select box with internationalized labels you have two options:

Assuming you have a Weekday enumeration com.mycompany.Weekday

package com.mycompany

enum Weekday {
	MONDAY,
	TUESDAY,
	WEDNESDAY,
	THURSDAY,
	FRIDAY
}

and the following messages

com.mycompany.Weekday.MONDAY = Monday
com.mycompany.Weekday.TUESDAY = Tuesday
com.mycompany.Weekday.WEDNESDAY = Wednesday
com.mycompany.Weekday.THURSDAY = Thursday
com.mycompany.Weekday.FRIDAY = Friday

1. Pass the valueMessagePrefix to the field tag.

<f:field property="weekday" 
         input-valueMessagePrefix="com.mycompany.Weekday" 
         input-noSelection="['':'- choose weekday -']" />

Please note the input- prefix which is used to pass attributes to the underlying tag.

2. Customize field rendering for all enumerations

Create the following GSP in grails-app/views/_fields/enum/_input.gsp

<g:select name="${property}"
		from="${type?.values()}"
 		keys="${type?.values()*.name()}"
 		value="${value}"
 		valueMessagePrefix="${type.name}" />

I prefer the 2nd option because you have to do it only once for all enumerations and the labels for an are probably the same whereever you use it.

Update 20.2.2013
The above code snippet doesn’t work if you are using a prefix, so I adjusted the name attribute. You can omit the keys attribute if you don’t override toString() of the enum.

<g:select name="${(prefix ?: '') + property}"
		from="${type?.values()}"
 		value="${value}"
 		valueMessagePrefix="${type.name}" />
Posted in Grails. Tags: . 1 Comment »

Grails: Listing the available message codes for errors

The following snippet is often used to list all errors of a form.

<g:eachError bean="${contactForm}">
     <li><g:message error="${it}" /></li>
</g:eachError>

If you do not specify any custom messages you will get the default ones. For example
Property [name] of class [class com.myCompany.ContactForm] cannot be blank

To overwrite the default message you have in Grails several possibilities which are too many to remember. So I’m using the following snippet to show which is the current error messsage and which codes would be possible.

<g:eachError bean="${contactForm}" var="error">
    ${error.field}: <g:message error="${error}" />
    <ul>
    <g:each in="${error.codes}" var="code">
        <li>${code}</li>
    </g:each>
    </ul>
</g:eachError>

Example output:

name: Property [name] of class [class com.myCompany.ContactFormCommand] cannot be blank

  • com.myCompany.ContactFormCommand.name.blank.error.com.myCompany.ContactFormCommand.name
  • com.myCompany.ContactFormCommand.name.blank.error.name
  • com.myCompany.ContactFormCommand.name.blank.error.java.lang.String
  • com.myCompany.ContactFormCommand.name.blank.error
  • contactFormCommand.name.blank.error.com.myCompany.ContactFormCommand.name
  • contactFormCommand.name.blank.error.name
  • contactFormCommand.name.blank.error.java.lang.String
  • contactFormCommand.name.blank.error
  • com.myCompany.ContactFormCommand.name.blank.com.myCompany.ContactFormCommand.name
  • com.myCompany.ContactFormCommand.name.blank.name
  • com.myCompany.ContactFormCommand.name.blank.java.lang.String
  • com.myCompany.ContactFormCommand.name.blank
  • contactFormCommand.name.blank.com.myCompany.ContactFormCommand.name
  • contactFormCommand.name.blank.name
  • contactFormCommand.name.blank.java.lang.String
  • contactFormCommand.name.blank
  • blank.com.myCompany.ContactFormCommand.name
  • blank.name
  • blank.java.lang.String
  • blank

So now you can easily choose the best message code.

References

Eclipse open GSP-page: Editor could not be initialized

I’m using Eclipse with the SpringSource Tool Suite. After importing a Grails Project, I wanted to open a GSP-page but got the following error in the Editor: Could not open the editor: Editor could not be initialized.

The stacktrace looks as follows:

java.lang.NullPointerException
    at com.springsource.sts.grails.editor.gsp.tags.GSPModelQueryCMProvider.(GSPModelQueryCMProvider.java:53)
    at com.springsource.sts.grails.editor.gsp.tags.GSPModelQueryImpl.(GSPModelQueryImpl.java:36)
    ...
    at org.eclipse.equinox.launcher.Main.main(Main.java:1287)

The error occurs because Eclipse (STS) wants to open GSP-files with the GSP Editor (because of File Associations) even if the project is not a Grails Project.

So the solution is to convert the project in a Grails Project: right click on your project → “Configure” | “Convert to Grails-Project”.

Resources:

Versions: Eclipse 3.5, STS 2.3, Grails 1.1.1

Posted in Grails. Tags: , , . Leave a Comment »

Grails and UrlRewriteFilter: Problem with Params

I’m using UrlRewriteFilter to map some legacy URLs to our new Grails application. It’s configured as follows:

web.xml

...
<filter>
    <filter-name>rewriteFilter</filter-name>
    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>charEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
    <filter-name>sitemesh</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter-mapping>
	<filter-name>rewriteFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>FORWARD</dispatcher>
</filter-mapping>

urlrwrite.xml

...
<rule>
	<from>^/legacy-search-url$</from>
	<to last="true">/search/result</to>
	<set type="parameter" name="pagesize">5</set>
</rule>

Now I had the problem that the forward worked as expected (SearchController with action “result” was invoked), but in params parameter pagesize was missing.

After a while of debugging I found out the following:
GrailsWebRequest, which holds the params is created with the GrailsWebRequestFilter. This filter is added to the web.xml in the controllers-plugin and the filter-mapping is placed at the end or after the charEncodingFilter. In my case after charEncodingFilter and so before the rewriteFilter:

generated web.xml

<filter-mapping>
    <filter-name>charEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
	<filter-name>grailsWebRequest</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>FORWARD</dispatcher>
	<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
	<filter-name>sitemesh</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
	<filter-name>rewriteFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>FORWARD</dispatcher>
</filter-mapping>

That means that the params-object is created before the rewriting happens, which explains that the pagesize parameter is not there. The solution is to place the rewriteFilter in first position of the filter-mapping or at least before the charEncodingFilter (if present).

Rethinking the problem I had the opinion that it should work regardless to the order, as the grailsWebRequest-filter has a forward dispatcher and should be called again after the rewriting. That’s correct so far, but as GrailsWebRequestFilter extends OncePerRequestFilter the GrailsWebRequest is not recreated on the second call.

Hint: If you are using the URL Rewrite Plugin, you will have the same problems, as it is loaded after the controllers-Plugin.

Versions: Grails 1.1.1

Posted in Grails. Tags: . 1 Comment »

Error in Grails documentation of URL Mappings exclude

In 6.4.6 Mapping Wildcards is written that you exclude URIs like this:

static excludes = ["/images/**", "/css/**"]

But this didn’t work for me. Looking at the source code (UrlMappingsFilter) I found out, that the exclude is no wildcard pattern matching and only a startsWith matching:

for (String excludePattern:excludePatterns){
    if (uri.equals(excludePattern)||
            (excludePattern.endsWith("*")&&
                    excludePattern.substring(0,excludePattern.length()-1).
                            regionMatches(0,uri,0,excludePattern.length()-1))){
        processFilterChain(request, response, filterChain);
        return;
    }
}

So the correct way is with one asterisk:

static excludes = ["/images/*", "/css/*"]