<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CEMBSHgyeyp7ImA9WxNUF0U.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185</id><updated>2009-11-09T17:00:59.693+01:00</updated><title>jan blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://jan-so.blogspot.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>81</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/blogspot/jan-so" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;A04MQHs4cCp7ImA9WxNVFko.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-1355405500454869320</id><published>2009-10-27T22:42:00.003+01:00</published><updated>2009-10-27T22:46:21.538+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-27T22:46:21.538+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>RSS Builder in Grails in a Few minutes</title><content type="html">&lt;p&gt;As I planned to include RSS feeds into &lt;a href="http://www.spenddaywithkids.com/"&gt;www.spenddaywithkids.com&lt;/a&gt; I needed possibility to create kind of RSS Builder. The good example of what I needed is &lt;a href="http://rss.icerocket.com/"&gt;IceRocket RSS Builder&lt;/a&gt;. So you are not generating RSS feeds directly from the data on your site but you are writing them manually. This way RSS feeds become kind of communication channel between the web site and users. &lt;/p&gt;  &lt;p&gt;I would stay with IceRocket but I couldn’t find possibility to do even simple formatting for RSS items. So my thought was let see how it is complicated to do it in Grails. And it turned out that it takes only few minutes to get very similar functionality. So here is short example done almost step by step.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; As my site is currently running on Grails 1.0.3 maybe not everything will be compatible with 1.1 version out of the box.&lt;/p&gt;  &lt;p&gt;So let go with implementation.&lt;/p&gt;  &lt;p&gt;First create grails application and named it rssbuilder.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;grails create-app rssbuilder&lt;/pre&gt;Then create two domain classes:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; RssChannel {&lt;br /&gt;   String name&lt;br /&gt;   String channelLink&lt;br /&gt;   String description&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;static&lt;/span&gt; constraints = {&lt;br /&gt;       name(blank:&lt;span class="kwrd"&gt;false&lt;/span&gt;, nullable:&lt;span class="kwrd"&gt;false&lt;/span&gt;, unique:&lt;span class="kwrd"&gt;true&lt;/span&gt;)&lt;br /&gt;       channelLink(blank:&lt;span class="kwrd"&gt;false&lt;/span&gt;, nullable:&lt;span class="kwrd"&gt;false&lt;/span&gt;, unique:&lt;span class="kwrd"&gt;false&lt;/span&gt;, url:&lt;span class="kwrd"&gt;true&lt;/span&gt;)&lt;br /&gt;       description(blank:&lt;span class="kwrd"&gt;true&lt;/span&gt;, nullable:&lt;span class="kwrd"&gt;true&lt;/span&gt;, maxSize:30000)&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; RssItem {&lt;br /&gt;   String title&lt;br /&gt;   String itemLink&lt;br /&gt;   String summary&lt;br /&gt;   RssChannel rssChannel&lt;br /&gt;   Date dateCreated&lt;br /&gt;   Date lastUpdated   &lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;static&lt;/span&gt; constraints = {&lt;br /&gt;       title(blank:&lt;span class="kwrd"&gt;false&lt;/span&gt;, nullable:&lt;span class="kwrd"&gt;false&lt;/span&gt;, unique:&lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;       itemLink(blank:&lt;span class="kwrd"&gt;false&lt;/span&gt;, nullable:&lt;span class="kwrd"&gt;false&lt;/span&gt;, unique:&lt;span class="kwrd"&gt;false&lt;/span&gt;, url:&lt;span class="kwrd"&gt;true&lt;/span&gt;)&lt;br /&gt;       summary(blank:&lt;span class="kwrd"&gt;false&lt;/span&gt;, nullable:&lt;span class="kwrd"&gt;false&lt;/span&gt;, unique:&lt;span class="kwrd"&gt;false&lt;/span&gt;, maxSize:50000)&lt;br /&gt;       rssChannel(blank:&lt;span class="kwrd"&gt;false&lt;/span&gt;, nullable:&lt;span class="kwrd"&gt;false&lt;/span&gt;, unique:&lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;Ah, don’t forget to install two plugins: &lt;a href="http://grails.org/plugin/feeds"&gt;Feeds Plugin&lt;/a&gt; and &lt;a href="http://grails.org/plugin/richui"&gt;RichUI plugin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now we can generate controllers and views for two domain classes:&lt;br /&gt;&lt;pre class="csharpcode"&gt;grails generate-all RssChannel&lt;br /&gt;grails generate-all RssItem&lt;/pre&gt;Well now if you start application you are able to specify RSS channel and items for RSS channel. To provide possibility to specify better formatting for RssItem we can reuse &amp;lt;richui:richTextEditor tag from the RichUI plugin. In the create and edit view of the RssItem change summary and bind it to the &lt;em&gt;richTextEditor&lt;/em&gt;. More or less you should &lt;em&gt;input &lt;/em&gt;tag with the following:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;richui:richTextEditor&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="summary"&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="${rssItem?.summary}"&lt;/span&gt; &lt;span class="attr"&gt;width&lt;/span&gt;&lt;span class="kwrd"&gt;="525"&lt;/span&gt; &lt;span class="attr"&gt;height&lt;/span&gt;&lt;span class="kwrd"&gt;="525"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;Now to generate RSS feed we can reuse functionality of the Feed plugin. So create FeedController class with command grails create-controller Feed.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The code of the feed controller should be:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    def rss = {&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;params&lt;/span&gt;.id) {&lt;br /&gt;           render &lt;span class="str"&gt;"missing id in params"&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       RssChannel rssChannel = RssChannel.get(&lt;span class="kwrd"&gt;new&lt;/span&gt; Long(&lt;span class="kwrd"&gt;params&lt;/span&gt;.id))&lt;br /&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt;(!rssChannel) {&lt;br /&gt;           render &lt;span class="str"&gt;"rss channel not found"&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       render(feedType:&lt;span class="str"&gt;"rss"&lt;/span&gt;, feedVersion:&lt;span class="str"&gt;"2.0"&lt;/span&gt;) {&lt;br /&gt;           title = rssChannel.name&lt;br /&gt;           link = rssChannel.channelLink&lt;br /&gt;           description = rssChannel.description&lt;br /&gt;           RssItem.findAllByRssChannel(rssChannel, [sort:&lt;span class="str"&gt;"dateCreated"&lt;/span&gt;, order:&lt;span class="str"&gt;"desc"&lt;/span&gt;]).each() { item -&amp;gt;&lt;br /&gt;               entry(item.title) {&lt;br /&gt;                   link=item.itemLink&lt;br /&gt;                   item.summary&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;       }&lt;br /&gt;   }&lt;/pre&gt;So now if you start application and create RSS channel and some items in that channel all you need to know is ID of that channel.&lt;br /&gt;&lt;p&gt;If the Id of the channel is e.g. 1 in the browser write &lt;a title="http://localhost:8080/rssbuilder/feed/rss/1" href="http://localhost:8080/rssbuilder/feed/rss/1"&gt;http://localhost:8080/rssbuilder/feed/rss/1&lt;/a&gt; and you will see your feed.&lt;/p&gt;&lt;p&gt;I believe this was really easy :)&lt;/p&gt;&lt;p&gt;As soon as I switch fun &lt;a href="http://www.spenddaywithkids.com"&gt;places to go with kids&lt;/a&gt; to the Grails 1.1 I will create plugin from this.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-1355405500454869320?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/B-FDv-57bcYoI5-KGcJih20DouQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/B-FDv-57bcYoI5-KGcJih20DouQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/B-FDv-57bcYoI5-KGcJih20DouQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/B-FDv-57bcYoI5-KGcJih20DouQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iw1BB0_eVdc:T83loOIvw_A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iw1BB0_eVdc:T83loOIvw_A:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iw1BB0_eVdc:T83loOIvw_A:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iw1BB0_eVdc:T83loOIvw_A:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iw1BB0_eVdc:T83loOIvw_A:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iw1BB0_eVdc:T83loOIvw_A:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iw1BB0_eVdc:T83loOIvw_A:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iw1BB0_eVdc:T83loOIvw_A:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iw1BB0_eVdc:T83loOIvw_A:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iw1BB0_eVdc:T83loOIvw_A:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/iw1BB0_eVdc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/1355405500454869320/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=1355405500454869320" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/1355405500454869320?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/1355405500454869320?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/iw1BB0_eVdc/rss-builder-in-grails-in-few-minutes.html" title="RSS Builder in Grails in a Few minutes" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/10/rss-builder-in-grails-in-few-minutes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYGRHcycSp7ImA9WxNVFUw.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-8848140398242397959</id><published>2009-10-26T00:06:00.003+01:00</published><updated>2009-10-26T00:08:45.999+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-26T00:08:45.999+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gsp" /><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>Grails scaffolding for domain classes in packages</title><content type="html">&lt;p&gt;While working on one simple subproject for &lt;a href="http://www.spenddaywithkids.com/"&gt;spend day with kids&lt;/a&gt; I got one interesting issue. I don't use scaffolding too often but this time I needed to get proof of concept. And I came to something where I am not sure if it is a bug or feature. And just to be clear this is happening with Grails version 1.0.3 and I am not sure if it is reproducible in later versions.&lt;/p&gt;  &lt;p&gt;Note: Having packages for domain classes is highly advisable and you should always use packages for all domain classes.   &lt;br /&gt;So let get to the point. I have create following domain class (please notice that package is defined).&lt;/p&gt;  &lt;pre class="csharpcode"&gt;com.jan.rssbuilder.domain.RssChannel&lt;/pre&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color:&lt;/style&gt;And after that I have created RssChannelController this way:&lt;br /&gt;&lt;pre class="csharpcode"&gt;package com.jan.rssbuilder.domain&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; RssChannelController {&lt;br /&gt;   def scaffold = &lt;span class="kwrd"&gt;true&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;After accessing this controller I got following exception:&lt;br /&gt;&lt;pre class="csharpcode"&gt;java.lang.IllegalStateException: Scaffolder supports action [index] &lt;span class="kwrd"&gt;for&lt;/span&gt; controller [com.jan.rssbuilder.domain.RssChannelController] but getAction returned &lt;span class="kwrd"&gt;null&lt;/span&gt;!&lt;/pre&gt;After changing controller by specifying domain class everything worked fine:&lt;br /&gt;&lt;pre class="csharpcode"&gt;package com.jan.rssbuilder.domain&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; RssChannelController {&lt;br /&gt;   def scaffold = com.jan.rssbuilder.domain.RssChannel&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-8848140398242397959?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/nKqKJp1-Vv1xhFlU1Mcfff9HfvQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nKqKJp1-Vv1xhFlU1Mcfff9HfvQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/nKqKJp1-Vv1xhFlU1Mcfff9HfvQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/nKqKJp1-Vv1xhFlU1Mcfff9HfvQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=rdBMPGFLlTQ:iTNklR5SOcA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=rdBMPGFLlTQ:iTNklR5SOcA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=rdBMPGFLlTQ:iTNklR5SOcA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=rdBMPGFLlTQ:iTNklR5SOcA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=rdBMPGFLlTQ:iTNklR5SOcA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=rdBMPGFLlTQ:iTNklR5SOcA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=rdBMPGFLlTQ:iTNklR5SOcA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=rdBMPGFLlTQ:iTNklR5SOcA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=rdBMPGFLlTQ:iTNklR5SOcA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=rdBMPGFLlTQ:iTNklR5SOcA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/rdBMPGFLlTQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/8848140398242397959/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=8848140398242397959" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/8848140398242397959?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/8848140398242397959?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/rdBMPGFLlTQ/grails-scaffolding-for-domain-classes.html" title="Grails scaffolding for domain classes in packages" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/10/grails-scaffolding-for-domain-classes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEABQXszfCp7ImA9WxNWGEQ.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-4955624883043985496</id><published>2009-10-18T22:10:00.002+02:00</published><updated>2009-10-18T22:12:30.584+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-18T22:12:30.584+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tips" /><category scheme="http://www.blogger.com/atom/ns#" term="gsp" /><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>Tips for working with front-end in Grails</title><content type="html">&lt;p&gt;I have implemented few web projects with Grails and some techniques while working with Grails front-end turned out to be better than other. When I didn’t follow them later on I usually had to refactor the code and did it the correct way.&lt;/p&gt;  &lt;p&gt;If you are reading this blog you noticed that I write very often about developing front-end with Grails. The reason is not that I am the best in the front-end but the reason is that I am the worst in the front-end. I am back-end developer and what I was missing in the majority of web frameworks was impossibility to make front-end more modular. In Grails this is easily to achieve thanks to &lt;a href="http://jan-so.blogspot.com/2008/06/make-gsp-readable-with-grails-templates.html"&gt;Grails templates and tags&lt;/a&gt;. And then you are almost to code in the normal java code.&lt;/p&gt;  &lt;p&gt;But come back to tips.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Tip 1:&lt;/strong&gt; Always create one gsp page per state of the result.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Tip 2:&lt;/strong&gt; Use templates and tags to make your pages more modular.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Tip 3:&lt;/strong&gt; When ever it gives sense send custom model classes to the gsp page (not the domain classes). &lt;/p&gt;  &lt;p&gt;Well tips are nothing without some example. As an example I will take my latest project &lt;a href="http://www.spenddaywithkids.com/"&gt;fun things to do with kids&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;In the first installment home page had following responsibilities:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;As a starting point for visitors&lt;/li&gt;    &lt;li&gt;To display found places to go with kids&lt;/li&gt;    &lt;li&gt;To inform user that the city provided cannot be uniquely  identified (there is more than one city with provided name)&lt;/li&gt;    &lt;li&gt;To inform user that no attractions were found around provided city&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;As you can see that is obvious break of the SRP (single responsibility principle). Because of too much responsibilities the model I was sending to the page was quite complex and the page contained number of &lt;em&gt;if&lt;/em&gt; blocks. And you must admit that having &lt;em&gt;if&lt;/em&gt; blocks in the html page is not the best practice. Another side effect was that page had about 300 lines that is simply too much.&lt;/p&gt;  &lt;p&gt;So what I did? Well, of course I did some refactoring. &lt;/p&gt;  &lt;p&gt;I have created one page per responsibility and depending on result controller decide which page to display and provides correct data model (is this maybe kind of strategy pattern?). This way it is much easier to understand what pages are doing. And now they are up to 30 lines long.&lt;/p&gt;  &lt;p&gt;But if you check pages you can see they are quite similar:&lt;/p&gt;  &lt;p&gt;To see home page navigate to: &lt;a href="http://www.spenddaywithkids.com/"&gt;spend day with kids&lt;/a&gt;   &lt;br /&gt;To see page with results navigate to: &lt;a href="http://www.spenddaywithkids.com/home/placesAroundLocation?locationName=nottingham&amp;amp;distance=20&amp;amp;orderBy=closest&amp;amp;_action_placesAroundLocation=Show+me"&gt;things to do with kids in Nottingham&lt;/a&gt;   &lt;br /&gt;To see page where there are multiple cities e.g. &lt;a href="http://www.spenddaywithkids.com/home/placesAroundLocation?locationName=Malinovo&amp;amp;distance=100&amp;amp;orderBy=closest&amp;amp;_action_placesAroundLocation=Show+me"&gt;search for Malinovo&lt;/a&gt;. Select Malinovo, Slovakia to see places to visit nearby my home :)   &lt;br /&gt;To see page where there are no results check e.g. for &lt;a href="http://www.spenddaywithkids.com/home/placesAroundLocation?locationName=belgrade&amp;amp;distance=100&amp;amp;orderBy=closest&amp;amp;_action_placesAroundLocation=Show+me"&gt;Belgrade&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;If you checked all these pages you can notice that they are very similar but little bit different. So how do you solve similarities. Very easy. Use &lt;strong&gt;templates and tags&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;And the last but not the least, it is obvious that the data models delivered to the pages can be quite different and even some cases need not to contain any domain classes.&lt;/p&gt;&lt;p&gt;So I hope that those tips will help you while working on your own grails projects.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-4955624883043985496?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/2qknhzHkxiLiA9cNnyZnwz23pLg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2qknhzHkxiLiA9cNnyZnwz23pLg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/2qknhzHkxiLiA9cNnyZnwz23pLg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/2qknhzHkxiLiA9cNnyZnwz23pLg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=U-MD7sRz0ig:JYaly3IpjUU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=U-MD7sRz0ig:JYaly3IpjUU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=U-MD7sRz0ig:JYaly3IpjUU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=U-MD7sRz0ig:JYaly3IpjUU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=U-MD7sRz0ig:JYaly3IpjUU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=U-MD7sRz0ig:JYaly3IpjUU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=U-MD7sRz0ig:JYaly3IpjUU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=U-MD7sRz0ig:JYaly3IpjUU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=U-MD7sRz0ig:JYaly3IpjUU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=U-MD7sRz0ig:JYaly3IpjUU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/U-MD7sRz0ig" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/4955624883043985496/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=4955624883043985496" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4955624883043985496?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4955624883043985496?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/U-MD7sRz0ig/tips-for-working-with-front-end-in.html" title="Tips for working with front-end in Grails" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/10/tips-for-working-with-front-end-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MBR3w-eip7ImA9WxNWF0U.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-1538566373491855198</id><published>2009-10-17T13:44:00.002+02:00</published><updated>2009-10-17T14:10:56.252+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-17T14:10:56.252+02:00</app:edited><title>New features on spend day with kids</title><content type="html">I have finally found some free time so I decided to implement some new features on &lt;a href="http://www.spenddaywithkids.com"&gt;spend day with kids&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So far all searches have been performed with the same default parameters. The defaults were distance is 100 kms and the sorting of attractions was by type.&lt;br /&gt;&lt;br /&gt;Very soon after the launch of the site I got mail from Jeff where he proposed that results should be displayed in the order of proximity from the provided city. I liked the idea immediately and now this feature is supported.&lt;br /&gt;&lt;br /&gt;So now you can provide city or even address and specify the distance of places to be searched and additionally to select ordering type. Possible ordering types are of course by distance and by city.&lt;br /&gt;&lt;br /&gt;As you probably know spend day with kids site helps you find great &lt;a href="http://www.spenddaywithkids.com"&gt;family days out&lt;/a&gt; and is implemented with Grails. While developing this site, so far I didn't hit any special interesting features that could be worth for blogging about. But if you have any ideas just let me know&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-1538566373491855198?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/0GCfxvy8WRcEhOKNiZFUPiBH6tM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0GCfxvy8WRcEhOKNiZFUPiBH6tM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/0GCfxvy8WRcEhOKNiZFUPiBH6tM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/0GCfxvy8WRcEhOKNiZFUPiBH6tM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iXH5j05Jymo:Fo64QUG3-NA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iXH5j05Jymo:Fo64QUG3-NA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iXH5j05Jymo:Fo64QUG3-NA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iXH5j05Jymo:Fo64QUG3-NA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iXH5j05Jymo:Fo64QUG3-NA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iXH5j05Jymo:Fo64QUG3-NA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iXH5j05Jymo:Fo64QUG3-NA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iXH5j05Jymo:Fo64QUG3-NA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iXH5j05Jymo:Fo64QUG3-NA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iXH5j05Jymo:Fo64QUG3-NA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/iXH5j05Jymo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/1538566373491855198/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=1538566373491855198" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/1538566373491855198?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/1538566373491855198?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/iXH5j05Jymo/new-features-on-spend-day-with-kids.html" title="New features on spend day with kids" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/10/new-features-on-spend-day-with-kids.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08GQHg8fyp7ImA9WxNWEU8.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-109239724362928665</id><published>2009-10-10T01:01:00.002+02:00</published><updated>2009-10-10T01:10:21.677+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-10T01:10:21.677+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><title>Hope to have more material for blogging</title><content type="html">I am aware that last few weeks I was quite lazy with blogging but as I was changing employer so lot of responsibilities have been in front of me. Of course, important part was knowledge transfer.  From the October I am in my new company.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First I would like to thanks my previous company for having a chance to work on interesting and exciting projects.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the new company I am coming to the position of Head of Software Development. It is a small start up company and we are working on the green field project. Yes, you see it right, its green field :)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As my future work will include some new technologies and different market I hope that I will have lot of materials for blogging. We will mainly work with affiliate networks and mobile web development. As this is quite new field for me I believe I will be able to share a lot of interesting discoveries.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As the field we will be working in is very dynamic we are of course on Scrum and agile software development. Dynamic projects and agile software development create great combination. I am very sure we will have lot of fun. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-109239724362928665?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/jUvoPXS6AaV5aWJG5M2JlC-0eRg/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jUvoPXS6AaV5aWJG5M2JlC-0eRg/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/jUvoPXS6AaV5aWJG5M2JlC-0eRg/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jUvoPXS6AaV5aWJG5M2JlC-0eRg/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=xURVOEPm4fM:Er_j8uqhmMw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=xURVOEPm4fM:Er_j8uqhmMw:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=xURVOEPm4fM:Er_j8uqhmMw:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=xURVOEPm4fM:Er_j8uqhmMw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=xURVOEPm4fM:Er_j8uqhmMw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=xURVOEPm4fM:Er_j8uqhmMw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=xURVOEPm4fM:Er_j8uqhmMw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=xURVOEPm4fM:Er_j8uqhmMw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=xURVOEPm4fM:Er_j8uqhmMw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=xURVOEPm4fM:Er_j8uqhmMw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/xURVOEPm4fM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/109239724362928665/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=109239724362928665" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/109239724362928665?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/109239724362928665?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/xURVOEPm4fM/hope-to-have-more-material-for-blogging.html" title="Hope to have more material for blogging" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/10/hope-to-have-more-material-for-blogging.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAEQXs9eyp7ImA9WxNXGUk.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-2697460949271810337</id><published>2009-10-07T22:13:00.002+02:00</published><updated>2009-10-07T22:18:20.563+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-07T22:18:20.563+02:00</app:edited><title>Software books reviews down - permanently (so far)</title><content type="html">It has been some time as I planned to take down software books reviews. Although I don't think that the idea was bad it takes time to make the site grow and support from the community was not so good.&lt;br /&gt;As running site takes some money, lot of time and I have two other sites online too: &lt;a href="http://www.grailstutorials.com"&gt;grails tutorials&lt;/a&gt; and &lt;a href="http://www.spenddaywithkids.com"&gt;things to do with kids&lt;/a&gt; I have to choose which one to take down.&lt;br /&gt;So my decision was to take down the software books reviews.&lt;br /&gt;&lt;br /&gt;Now I want to be able to concentrate on my new work and to try to extend functionality of the spend day with kids site. I promised few months ago that I will open source grails tutorials and I still plan to do that. The problem is that I need few days of additional work before I open source it and I am not able to find those day.&lt;br /&gt;&lt;br /&gt;So for all that were visiting software books reviews, sorry but I had to take it down.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-2697460949271810337?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/HJb-I5_m7dWKcB-0y3IJ11Khk-o/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HJb-I5_m7dWKcB-0y3IJ11Khk-o/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/HJb-I5_m7dWKcB-0y3IJ11Khk-o/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HJb-I5_m7dWKcB-0y3IJ11Khk-o/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=tLAB2-KBjp8:_r6ZuZESyKk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=tLAB2-KBjp8:_r6ZuZESyKk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=tLAB2-KBjp8:_r6ZuZESyKk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=tLAB2-KBjp8:_r6ZuZESyKk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=tLAB2-KBjp8:_r6ZuZESyKk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=tLAB2-KBjp8:_r6ZuZESyKk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=tLAB2-KBjp8:_r6ZuZESyKk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=tLAB2-KBjp8:_r6ZuZESyKk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=tLAB2-KBjp8:_r6ZuZESyKk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=tLAB2-KBjp8:_r6ZuZESyKk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/tLAB2-KBjp8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/2697460949271810337/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=2697460949271810337" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/2697460949271810337?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/2697460949271810337?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/tLAB2-KBjp8/software-books-reviews-down-permanently.html" title="Software books reviews down - permanently (so far)" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/10/software-books-reviews-down-permanently.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUECSX0yeSp7ImA9WxNXEEU.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-9099364544023818346</id><published>2009-09-27T22:32:00.003+02:00</published><updated>2009-09-27T22:34:28.391+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-27T22:34:28.391+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>Getting data into Grails tags and templates</title><content type="html">&lt;p&gt;In the post describing &lt;a href="http://jan-so.blogspot.com/2008/06/make-gsp-readable-with-grails-templates.html"&gt;how to create and use grails templates and tags&lt;/a&gt; I made short example that showed how gsp pages can be readable if you are using tags and templates. One of the questions asked in comments was how do I get data into tag and/or template. Instead writing answer as comment I decided to write the whole post.   &lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Scoped variables&lt;/strong&gt;   &lt;br /&gt;Common way to get data into tag and template is using Grails &lt;strong&gt;scoped variables like&lt;/strong&gt; application, session, request. This means that both, tags and templates, have access to those variables so you can use them.    &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Templates    &lt;br /&gt;&lt;/strong&gt;To send data into templates you can and should use standard approach with the grails model.&lt;/p&gt;  &lt;p&gt;For example if you are rendering template from tag or from controller (or some groovy code) you should use construct like this one:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;render(template:&lt;span class="str"&gt;"/templates/common/messageBoxTemplate"&lt;/span&gt;, model:[title:"hello world"])&lt;/pre&gt;&lt;p&gt;If you are rendering template from gsp page you should use construct like this one (actually taken from grails documentation):&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:render&lt;/span&gt; &lt;span class="attr"&gt;template&lt;/span&gt;&lt;span class="kwrd"&gt;="displaybook"&lt;/span&gt; &lt;span class="attr"&gt;model&lt;/span&gt;&lt;span class="kwrd"&gt;="['book':book,'author':author]"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;To be honest I try to avoid using &lt;em&gt;&amp;lt;g:render...&lt;/em&gt; from gsp pages because if you are using tags it is easier to read the gsp page. Another advantage of using tags is that it is easier to refactor the gsp pages. So when you find yourself writing &lt;em&gt;&amp;lt;g:render template...&lt;/em&gt;. in the gsp page, introduce grails tag for that.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tags&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The advantage of tags is that they have access to the &lt;strong&gt;GORM classes&lt;/strong&gt; and you can inject any &lt;strong&gt;grails service&lt;/strong&gt; into tag. So if you need to perform some calculation that needs to be displayed on the gsp page tag is the right place for that.&lt;/p&gt;&lt;p&gt;Another way to send data into grails is via &lt;strong&gt;attrs&lt;/strong&gt; map. Each tag is specified in the file ending with TagLib and the format of the tag is:&lt;/p&gt;&lt;pre class="csharpcode"&gt;def messageBox = {attrs, body -&amp;gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;out&lt;/span&gt; &amp;lt;&amp;lt; render(template:&lt;span class="str"&gt;"/templates/common/messageBoxTemplate"&lt;/span&gt;, model:[title:attrs.title, body:body()])&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;So tag is closure with two variables: attrs and body. Using attrs you can access any custom data sent to the tag.&lt;/p&gt;&lt;p&gt;So how do we send that data?&lt;/p&gt;&lt;p&gt;When displaying tag from the gsp page you are using construct like this one:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&amp;lt;g:messageBox title=&lt;span class="str"&gt;"Register, it takes only seconds"&lt;/span&gt;&amp;gt;&lt;/pre&gt;&lt;p&gt;In this case the title is custom data sent to the tag.&lt;/p&gt;&lt;p&gt;To execute given tag from the controller or some other groovy code you can use construct like this one:&lt;/p&gt;&lt;pre class="csharpcode"&gt;g.messageBox(title:&lt;span class="str"&gt;"Register, it takes only seconds"&lt;/span&gt;) {&lt;br /&gt;  &lt;span class="rem"&gt;//body to be displayed&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;So for example, to display number of registered users on the &lt;a href="http://www.grailstutorials.com/"&gt;grails and groovy tutorials&lt;/a&gt; page I am using direct access to database from the tag and then sending those data to the model. But I could also create e.g. application scoped variable for this and gain some performance. So currently the code in the tag looks like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;def dataInfo = {attrs, body -&amp;gt;&lt;br /&gt;   def postsCount = TutorialLink.count()&lt;br /&gt;   def userCount = User.count()&lt;br /&gt;   &lt;span class="kwrd"&gt;out&lt;/span&gt; &amp;lt;&amp;lt; render(template:&lt;span class="str"&gt;"/templates/common/statsTemplate"&lt;/span&gt;, model:[userCount:userCount, postsCount:postsCount])&lt;br /&gt;}&lt;/pre&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-9099364544023818346?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/wVL4O7WinMdn8jbW0iusUal1T_I/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wVL4O7WinMdn8jbW0iusUal1T_I/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/wVL4O7WinMdn8jbW0iusUal1T_I/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wVL4O7WinMdn8jbW0iusUal1T_I/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=qTpoAqQAHBE:6mQUIi2YdJ0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=qTpoAqQAHBE:6mQUIi2YdJ0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=qTpoAqQAHBE:6mQUIi2YdJ0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=qTpoAqQAHBE:6mQUIi2YdJ0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=qTpoAqQAHBE:6mQUIi2YdJ0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=qTpoAqQAHBE:6mQUIi2YdJ0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=qTpoAqQAHBE:6mQUIi2YdJ0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=qTpoAqQAHBE:6mQUIi2YdJ0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=qTpoAqQAHBE:6mQUIi2YdJ0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=qTpoAqQAHBE:6mQUIi2YdJ0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/qTpoAqQAHBE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/9099364544023818346/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=9099364544023818346" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/9099364544023818346?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/9099364544023818346?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/qTpoAqQAHBE/getting-data-into-grails-tags-and.html" title="Getting data into Grails tags and templates" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/09/getting-data-into-grails-tags-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUCRnw8fSp7ImA9WxNTFEs.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-4899115002643797949</id><published>2009-08-17T00:37:00.001+02:00</published><updated>2009-08-17T00:37:47.275+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-17T00:37:47.275+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="tdd" /><category scheme="http://www.blogger.com/atom/ns#" term="architecture" /><title>Agile, TDD and upfront desing</title><content type="html">As TDD and agile software development are emerging as more and more used technologies for software development lot of software developers are jumping into it without having real knowledge.&lt;br /&gt;&lt;br /&gt;From my point of view one of the misconceptions about TDD and agile is that you don't need any design and architecture upfront. TDD with refactoring will give me the right architecture in all cases.&lt;br /&gt;&lt;br /&gt;Although I am big fun of agile software development I don't believe this is idea of the agile. Agile is here to help develop better software for better customer satisfaction. But it in no cases claims that you should forget about big picture, about documentation and about having at least basic understanding of your system design.&lt;br /&gt;&lt;br /&gt;From my point of view you need to do basic design at least at the high level. Then for important parts you need to go to lower levels (if really necessary).  And then agile together with TDD will help you to really get it right. To separate concerns, to make separation between domain objects in different tiers and so on.&lt;br /&gt;&lt;br /&gt;So as conclusion, agile does not mean no more thinking. Agile means think about the problem, do basic planning and then use TDD and other agile tools to get it right.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-4899115002643797949?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/a-YLRcvHEx77Jkgqn0tPFy9t26E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a-YLRcvHEx77Jkgqn0tPFy9t26E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/a-YLRcvHEx77Jkgqn0tPFy9t26E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/a-YLRcvHEx77Jkgqn0tPFy9t26E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Fg1Kgt9EYiU:hVGsj1K82Pk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Fg1Kgt9EYiU:hVGsj1K82Pk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Fg1Kgt9EYiU:hVGsj1K82Pk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Fg1Kgt9EYiU:hVGsj1K82Pk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Fg1Kgt9EYiU:hVGsj1K82Pk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Fg1Kgt9EYiU:hVGsj1K82Pk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Fg1Kgt9EYiU:hVGsj1K82Pk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Fg1Kgt9EYiU:hVGsj1K82Pk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Fg1Kgt9EYiU:hVGsj1K82Pk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Fg1Kgt9EYiU:hVGsj1K82Pk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/Fg1Kgt9EYiU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/4899115002643797949/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=4899115002643797949" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4899115002643797949?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4899115002643797949?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/Fg1Kgt9EYiU/agile-tdd-and-upfront-desing.html" title="Agile, TDD and upfront desing" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/08/agile-tdd-and-upfront-desing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0IMQnc5fip7ImA9WxJaGEg.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-6270942389413305228</id><published>2009-08-10T00:05:00.002+02:00</published><updated>2009-08-10T00:06:23.926+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-10T00:06:23.926+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>g:form, g:actionSubmit and Internet Explorer 8</title><content type="html">&lt;p&gt;While working on my latest grails powered web site &lt;a href="http://www.spenddaywithkids.com/"&gt;things to do with kids&lt;/a&gt; I have noticed that one form performs ok in Firefox and Chrome but not in Internet Explorer.  If this would be case with &lt;a href="http://www.grailstutorials.com/"&gt;grails tutorials&lt;/a&gt; I wouldn't care too much because majority of visitors have Firefox or Chrome. But my statistics for things to do with kids are showing that there is more visitors using IE than other browsers.&lt;/p&gt;  &lt;p&gt;The problem was following. E.g. on the home page of &lt;a href="http://www.spenddaywithkids.com/"&gt;things to do with kids&lt;/a&gt; you enter the city name and then press enter on your keyboard. In Firefox and Chrome you get the list of places to visit but in IE8 nothing happened.&lt;/p&gt;  &lt;p&gt;But if you used tab to move focus on the Show Me button then everything worked also in IE. &lt;/p&gt;  &lt;p&gt;The initial code looked like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:form&lt;/span&gt; &lt;span class="attr"&gt;controller&lt;/span&gt;&lt;span class="kwrd"&gt;="home"&lt;/span&gt; &lt;span class="attr"&gt;method&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;input&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="locationName"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-10 last"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:actionSubmit&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="Show me"&lt;/span&gt; &lt;span class="attr"&gt;action&lt;/span&gt;&lt;span class="kwrd"&gt;="placesAroundLocation"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;g:form&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;After some investigation I noticed that closure called from IE was actually &lt;em&gt;index&lt;/em&gt; in the HomeController. So this means that in IE8 when enter is pressed while focus is in the input box default action of the controller is called while in Firefox and Chrome action of the button was called.&lt;/p&gt;&lt;p&gt;So to fix the problem with the IE I have slightly change the code. I added form default action so now it looks like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:form&lt;/span&gt; &lt;span class="attr"&gt;controller&lt;/span&gt;&lt;span class="kwrd"&gt;="home"&lt;/span&gt; &lt;span class="attr"&gt;action&lt;/span&gt;&lt;span class="kwrd"&gt;="placesAroundLocation"&lt;/span&gt; &lt;span class="attr"&gt;method&lt;/span&gt;&lt;span class="kwrd"&gt;="GET"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;input&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="locationName"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-10 last"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:actionSubmit&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="Show me"&lt;/span&gt; &lt;span class="attr"&gt;action&lt;/span&gt;&lt;span class="kwrd"&gt;="placesAroundLocation"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;g:form&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;I didn't check behavior in other versions of IE but if you have similar problem this may help you.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-6270942389413305228?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/jFlpM33olb5-CWtRgD_Zd-Fukd4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jFlpM33olb5-CWtRgD_Zd-Fukd4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/jFlpM33olb5-CWtRgD_Zd-Fukd4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/jFlpM33olb5-CWtRgD_Zd-Fukd4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=hEnsxE3wOvY:toyfdHM4NMg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=hEnsxE3wOvY:toyfdHM4NMg:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=hEnsxE3wOvY:toyfdHM4NMg:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=hEnsxE3wOvY:toyfdHM4NMg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=hEnsxE3wOvY:toyfdHM4NMg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=hEnsxE3wOvY:toyfdHM4NMg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=hEnsxE3wOvY:toyfdHM4NMg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=hEnsxE3wOvY:toyfdHM4NMg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=hEnsxE3wOvY:toyfdHM4NMg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=hEnsxE3wOvY:toyfdHM4NMg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/hEnsxE3wOvY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/6270942389413305228/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=6270942389413305228" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/6270942389413305228?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/6270942389413305228?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/hEnsxE3wOvY/gform-gactionsubmit-and-internet.html" title="g:form, g:actionSubmit and Internet Explorer 8" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/08/gform-gactionsubmit-and-internet.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcEQXc5fyp7ImA9WxJbF04.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-7525754428216808987</id><published>2009-07-28T00:11:00.002+02:00</published><updated>2009-07-28T00:33:20.927+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-28T00:33:20.927+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>You don't need session in Grails service</title><content type="html">From time to time there are questions or blog posts that explain how to obtain access to web session from the grails service or domain class. If you really need to access session from the service class e.g. &lt;a href="http://robertbjarum.blogspot.com/2008/10/accessing-session-httpsession-from.html"&gt;this&lt;/a&gt; post from Robert can help you.&lt;br /&gt;&lt;br /&gt;But before you start reusing session in your services or even domain classes be careful and think if you really want that. Service should be more or less simple Java class and when ever possible should not depend on special environment classes. And session is actually very special web application environment class.&lt;br /&gt;&lt;br /&gt;So what to do if in the service you really need that value from the session? Well the answer is of course very simple. Send it as a method parameter. Or another way is Robert's approach to create service that will return that value from session and inject it into service that really needs that value.&lt;br /&gt;&lt;br /&gt;This way your services will not depend on the web container context and you can easily port them to other environment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-7525754428216808987?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/68mQyJc6C1S52XQQPiPrGkOOh5A/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/68mQyJc6C1S52XQQPiPrGkOOh5A/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/68mQyJc6C1S52XQQPiPrGkOOh5A/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/68mQyJc6C1S52XQQPiPrGkOOh5A/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=mtJ26TOtVig:ipSEtrgQNfk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=mtJ26TOtVig:ipSEtrgQNfk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=mtJ26TOtVig:ipSEtrgQNfk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=mtJ26TOtVig:ipSEtrgQNfk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=mtJ26TOtVig:ipSEtrgQNfk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=mtJ26TOtVig:ipSEtrgQNfk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=mtJ26TOtVig:ipSEtrgQNfk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=mtJ26TOtVig:ipSEtrgQNfk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=mtJ26TOtVig:ipSEtrgQNfk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=mtJ26TOtVig:ipSEtrgQNfk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/mtJ26TOtVig" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/7525754428216808987/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=7525754428216808987" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/7525754428216808987?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/7525754428216808987?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/mtJ26TOtVig/you-dont-need-session-in-grails-service.html" title="You don't need session in Grails service" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/07/you-dont-need-session-in-grails-service.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IMQ38-eyp7ImA9WxJbEU8.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-6469053568702311148</id><published>2009-07-21T00:36:00.002+02:00</published><updated>2009-07-21T00:39:42.153+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-21T00:39:42.153+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>UK included on spend day with kids</title><content type="html">As you may know few weeks ago I have launched &lt;a href="http://www.spenddaywithkids.com"&gt;spend day with kids&lt;/a&gt; web site. In the first release only USA was covered but yesterday I have finished entering attractions for UK.&lt;br /&gt;&lt;br /&gt;So please feel invited to visit spenddaywithkids.com and search for ideal places to have a day full of fun with your kids.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-6469053568702311148?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/G6N0JQQffm8b284-3B2kR9HLs64/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/G6N0JQQffm8b284-3B2kR9HLs64/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/G6N0JQQffm8b284-3B2kR9HLs64/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/G6N0JQQffm8b284-3B2kR9HLs64/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Dwt8Ow8H3CI:4ID9xtAICao:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Dwt8Ow8H3CI:4ID9xtAICao:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Dwt8Ow8H3CI:4ID9xtAICao:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Dwt8Ow8H3CI:4ID9xtAICao:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Dwt8Ow8H3CI:4ID9xtAICao:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Dwt8Ow8H3CI:4ID9xtAICao:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Dwt8Ow8H3CI:4ID9xtAICao:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Dwt8Ow8H3CI:4ID9xtAICao:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Dwt8Ow8H3CI:4ID9xtAICao:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Dwt8Ow8H3CI:4ID9xtAICao:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/Dwt8Ow8H3CI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/6469053568702311148/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=6469053568702311148" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/6469053568702311148?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/6469053568702311148?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/Dwt8Ow8H3CI/uk-included-on-spend-day-with-kids.html" title="UK included on spend day with kids" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/07/uk-included-on-spend-day-with-kids.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkAGRHkyfip7ImA9WxJUGEs.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-984920797029620060</id><published>2009-07-17T23:01:00.004+02:00</published><updated>2009-07-17T23:05:25.796+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-17T23:05:25.796+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="groovy" /><title>Groovy and Grails help build apps faster</title><content type="html">Actually this is not my post but a very interesting article about productivity gained using Grails and Groovy.&lt;br /&gt;&lt;br /&gt;Usually I am not posting links to other articles but my feeling is that this one deserves this.  I didn't notice link to this articles on other grails/groovy related sites so I want to share it.&lt;br /&gt;&lt;br /&gt;So navigate to "&lt;a href="http://www.ciol.com/developer/languages/news-reports/groovy-and-grails-help-build-apps-faster/10709122151/0/"&gt;Groovy and Grails help build apps faster&lt;/a&gt;" to read the whole case.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-984920797029620060?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/EnOcmPHYQI2Fo4zoqqYQWhK4YoQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EnOcmPHYQI2Fo4zoqqYQWhK4YoQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/EnOcmPHYQI2Fo4zoqqYQWhK4YoQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/EnOcmPHYQI2Fo4zoqqYQWhK4YoQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Z1FqDO9Mozo:ywsFKbVRNro:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Z1FqDO9Mozo:ywsFKbVRNro:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Z1FqDO9Mozo:ywsFKbVRNro:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Z1FqDO9Mozo:ywsFKbVRNro:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Z1FqDO9Mozo:ywsFKbVRNro:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Z1FqDO9Mozo:ywsFKbVRNro:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Z1FqDO9Mozo:ywsFKbVRNro:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Z1FqDO9Mozo:ywsFKbVRNro:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Z1FqDO9Mozo:ywsFKbVRNro:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Z1FqDO9Mozo:ywsFKbVRNro:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/Z1FqDO9Mozo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/984920797029620060/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=984920797029620060" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/984920797029620060?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/984920797029620060?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/Z1FqDO9Mozo/groovy-and-grails-help-build-apps.html" title="Groovy and Grails help build apps faster" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/07/groovy-and-grails-help-build-apps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMMSHk8cSp7ImA9WxJVGE0.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-4369101578921351457</id><published>2009-07-05T16:07:00.004+02:00</published><updated>2009-07-05T16:34:49.779+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-05T16:34:49.779+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>Spend day with kids Grails web app launched</title><content type="html">I have launched new Grails powered web site &lt;a href="http://www.spenddaywithkids.com/"&gt;www.spenddaywithkids.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Idea of the web site is to help you find interesting places where you can go with kids. There are places like zoos, water parks, theme parks....&lt;br /&gt;&lt;br /&gt;Developing this application was interesting for me because this was for me the first time I used google maps in some of my application. Also new for me was geocoding but actually this turned out to be as easy as reuse formulas available online. Currently on USA is covered but Europe should come soon.&lt;br /&gt;&lt;br /&gt;Currently I have three sites online: &lt;a href="http://www.grailstutorials.com/"&gt;grails tutorials&lt;/a&gt;, &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt; and &lt;a href="http://www.spenddaywithkids.com/"&gt;spend day with kids&lt;/a&gt;.&lt;br /&gt;For me it is just prove that development of web applications with Grails is easy and fun but know I will concentrate on extending my existing site and hope I will not get any fun idea soon :)&lt;br /&gt;&lt;br /&gt;Let me know if you have some proposals for any of mentioned sites.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-4369101578921351457?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-If6LspA-IDn8rP9rTOZIPUXRlc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-If6LspA-IDn8rP9rTOZIPUXRlc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-If6LspA-IDn8rP9rTOZIPUXRlc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-If6LspA-IDn8rP9rTOZIPUXRlc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=7h5B8eKDpKs:5ZnWnAXOWy0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=7h5B8eKDpKs:5ZnWnAXOWy0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=7h5B8eKDpKs:5ZnWnAXOWy0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=7h5B8eKDpKs:5ZnWnAXOWy0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=7h5B8eKDpKs:5ZnWnAXOWy0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=7h5B8eKDpKs:5ZnWnAXOWy0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=7h5B8eKDpKs:5ZnWnAXOWy0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=7h5B8eKDpKs:5ZnWnAXOWy0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=7h5B8eKDpKs:5ZnWnAXOWy0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=7h5B8eKDpKs:5ZnWnAXOWy0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/7h5B8eKDpKs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/4369101578921351457/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=4369101578921351457" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4369101578921351457?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4369101578921351457?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/7h5B8eKDpKs/spend-day-with-kids-grails-web-app.html" title="Spend day with kids Grails web app launched" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/07/spend-day-with-kids-grails-web-app.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIHQX86eSp7ImA9WxJVE0Q.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-2638978241328718854</id><published>2009-06-30T22:50:00.003+02:00</published><updated>2009-06-30T23:32:10.111+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-30T23:32:10.111+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="book review" /><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>Book Review: Grails in Action</title><content type="html">I was lucky enough to get copy of the book &lt;a href="http://www.amazon.com/gp/product/1933988932?ie=UTF8&amp;amp;tag=janblog-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1933988932"&gt;Grails in Action&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=janblog-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=1933988932" alt="" style="border: medium none  ! important; margin: 0px ! important;" border="0" width="1" height="1" /&gt; from Manning. And of course I have promised to write review of the book.&lt;br /&gt;&lt;br /&gt;My feelings about the book are somehow mixed. Basically book is divided into four parts:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Introducing Grails&lt;/li&gt;&lt;li&gt;Core Grails&lt;/li&gt;&lt;li&gt;Everyday Grails&lt;/li&gt;&lt;li&gt;Advanced Grails&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;The first two parts&lt;/span&gt;, Introducing Grails and Core Grails, are for more or less newcomers to the Grails so if you already have experience with Grails they are somehow boring. That wouldn't be a problem if my opinion wouldn't be that they are not written in an appropriate way for the Grails/Groovy beginners. My feeling is that beginners will get confused as the authors jump too much directly into action. So my advice for the beginners is to read e.g. Getting Started with Grails and then come back to the book Grails in Action.&lt;br /&gt;&lt;br /&gt;But even if you already have Grails experience don't just skip over the first two parts, because after having some Grails foundation the first two parts become very useful and very easy understandable. Even for me (and I have some experience with Grails) there were useful information and discoveries.&lt;br /&gt;&lt;br /&gt;Very good approach in this two parts from the authors is that they have devoted lot of energy to explain how to test Grails application. This is something I should definitely start to do on my own projects :)&lt;br /&gt;&lt;br /&gt;The real fun comes with the &lt;span style="font-weight: bold;"&gt;second two parts&lt;/span&gt; - Everyday Grails and Advanced Grails. I have really enjoyed reading chapters from those parts. They are very nice and are really covering lot of skills you will need during real Grails projects.&lt;br /&gt;&lt;br /&gt;In the &lt;span style="font-weight: bold;"&gt;third part&lt;/span&gt; authors are explaining how not to reinvent wheel by using number of available plugins. They show you how to fast and reliably put together advance features by reusing already existing functionality. I liked this approach and using it myself a lot.&lt;br /&gt;There are also chapters devoted to workflows, exposing interface to outside world and using messaging.&lt;br /&gt;&lt;br /&gt;After finishing third part you have really solid foundation to do some serious Grails development.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-weight: bold;"&gt;fourth part&lt;/span&gt; is really advanced although I would include basic transactional behavior into at least third part of the book as this is probably more everyday grails than advanced grails. The fourth part will explain advance GORM related features, advance usage of spring and something you will for sure meet in the corporate environment - build and deploy process.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;At the end I was very happy that I got a chance to read this book. This book will lead you from the beggining to the really advanced features of the Grails. If you are developing with Grails I am very sure you will have this book near you.&lt;br /&gt;If you are just starting with Grails I would recommend, first read something simplier and then come back to this book. I am sure you will enjoy reading it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And if you want to buy the book you can do it here :)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=janblog-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=1933988932&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-2638978241328718854?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/RWk0PiBtPs3-n21QGrOCQQz4YTY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/RWk0PiBtPs3-n21QGrOCQQz4YTY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/RWk0PiBtPs3-n21QGrOCQQz4YTY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/RWk0PiBtPs3-n21QGrOCQQz4YTY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=z1y9gBvELtg:2SWSrmvLTgc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=z1y9gBvELtg:2SWSrmvLTgc:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=z1y9gBvELtg:2SWSrmvLTgc:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=z1y9gBvELtg:2SWSrmvLTgc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=z1y9gBvELtg:2SWSrmvLTgc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=z1y9gBvELtg:2SWSrmvLTgc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=z1y9gBvELtg:2SWSrmvLTgc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=z1y9gBvELtg:2SWSrmvLTgc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=z1y9gBvELtg:2SWSrmvLTgc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=z1y9gBvELtg:2SWSrmvLTgc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/z1y9gBvELtg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/2638978241328718854/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=2638978241328718854" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/2638978241328718854?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/2638978241328718854?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/z1y9gBvELtg/book-review-grails-in-action.html" title="Book Review: Grails in Action" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/06/book-review-grails-in-action.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MCQHczeCp7ImA9WxJXGUU.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-3613323550855710617</id><published>2009-06-14T15:00:00.005+02:00</published><updated>2009-06-14T16:24:21.980+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-14T16:24:21.980+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="book review" /><title>Book Review: Becoming Agile</title><content type="html">When I started to think that majority of agile books are somehow breaking DRY (don't repeat yourself) principle I was lucky enough to get a copy of the book &lt;a href="http://www.amazon.com/gp/product/1933988258?ie=UTF8&amp;amp;tag=janblog-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1933988258"&gt;Becoming Agile: ...in an imperfect world&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=janblog-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=1933988258" alt="" style="border: medium none  ! important; margin: 0px ! important;" width="1" border="0" height="1" /&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What I liked the most in this book is that it is completely oriented to the real world. Therefore it will not try to teach you any of the existing agile frameworks but will help you to make your company (team) agile taking into account all constraints surrounding you. Book is oriented around agile principles and authors consider you environment agile if you are following agile manifesto principles.&lt;br /&gt;Another value of the book is that agile introduction is taken  from the complete beginning. From company readiness  assessment up to the project deployment and spreading your agile process through out the whole company. The whole project lifecycle is covered. From the vision, through adapting idea to the deployment. This is something that I was missing the most in lot of books about agile.&lt;br /&gt;&lt;br /&gt;Book follows imaginary company Acme media and its move toward more agile environment.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Getting started&lt;/span&gt; chapter will explain how to check your company readiness to adopt agile processes, ensure buy-in and inject agility into your existing process. When you have selected pilot project you are moving forward.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Kicking off&lt;/span&gt;&lt;/span&gt; chapter explains how to make feasibility study and how to decide if you should continue or stop with the project.&lt;br /&gt;&lt;br /&gt;If you decided to continue with the project &lt;span style="font-weight: bold;"&gt;Populating the product backlog&lt;/span&gt; chapter will show how to create product backlog, what means "just enough" for a feature card and how to estimate and prioritize the product backlog.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Enough information for scheduling&lt;/span&gt; creates release plan and explains in how much details you should plan your iterations. And don't forget that having plan is not enough. What you need is planning because during the project your plan will change for sure.&lt;br /&gt;&lt;br /&gt;When you have release and iteration plan you can move to the &lt;span style="font-weight: bold;"&gt;Building the product&lt;/span&gt; chapter. You will see how to welcome change, how to apply agile principles into development and how to ensure that you have working software at the end of iteration.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Embracing change&lt;/span&gt; chapter cope with adapting to change requirements. It explains common reasons for requirement changes and how to adapt to them. Next parts of this chapter will show you how to plan deploying and how to improve your process using retrospective.&lt;br /&gt;&lt;br /&gt;If your pilot project was successful you will want to spread the agile process throughout the company. The &lt;span style="font-weight: bold;"&gt;Moving forward&lt;/span&gt; chapter will help you with this process.&lt;br /&gt;&lt;br /&gt;Rest of the book explains the whole process from two different points of view. In one chapter the overall diagram of the project lifecycle is displayed and shortly explained while another chapter contains text description of the overall process.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;Although at the beginning I was not sure if I want to read this book I must admit I have really enjoyed reading the book. I believe that this book must be mandatory read for anyone who want to become member of agile community.&lt;br /&gt;The only downside of the book is that it covers really wide area (complete project lifecycle) and thus after reading this book you will need to read other books to improve your knowledge about e.g. estimating, testing, writing good user stories...&lt;br /&gt;&lt;br /&gt;I really recommend this book to everyone that already are or want to enter the agile world.&lt;br /&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=janblog-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=1933988258&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-3613323550855710617?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/HfwWLrtIUSqbiDxKo2VhyM69iCA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HfwWLrtIUSqbiDxKo2VhyM69iCA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/HfwWLrtIUSqbiDxKo2VhyM69iCA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/HfwWLrtIUSqbiDxKo2VhyM69iCA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=bvhA6vHeRD4:gmzi47el7Vs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=bvhA6vHeRD4:gmzi47el7Vs:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=bvhA6vHeRD4:gmzi47el7Vs:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=bvhA6vHeRD4:gmzi47el7Vs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=bvhA6vHeRD4:gmzi47el7Vs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=bvhA6vHeRD4:gmzi47el7Vs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=bvhA6vHeRD4:gmzi47el7Vs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=bvhA6vHeRD4:gmzi47el7Vs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=bvhA6vHeRD4:gmzi47el7Vs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=bvhA6vHeRD4:gmzi47el7Vs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/bvhA6vHeRD4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/3613323550855710617/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=3613323550855710617" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/3613323550855710617?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/3613323550855710617?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/bvhA6vHeRD4/book-review-becoming-agile.html" title="Book Review: Becoming Agile" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/06/book-review-becoming-agile.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYCRHY9fCp7ImA9WxJRF0o.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-7090526925832699359</id><published>2009-05-19T23:54:00.002+02:00</published><updated>2009-05-19T23:56:05.864+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-19T23:56:05.864+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>Analyzing domain of the problem - GORM classes</title><content type="html">&lt;p&gt;&lt;strong&gt;[From the series - creating &lt;/strong&gt;&lt;a href="http://www.softwarebooksreviews.com/"&gt;&lt;strong&gt;software books reviews&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; grails web application]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In the previous posts I have created basic empty grails application. All the steps done to get up to this point are linked in &lt;a href="http://jan-so.blogspot.com/2009/04/series-from-developing-software-books.html"&gt;this post&lt;/a&gt;. When the basic layout of the application is prepared it is obviously time to analyze domain objects. Domain objects in the grails are called GORM (grail's object relational mapping). Database schema is automatically generated from GORM objects and they probably represent the most powerful feature of the grails framework. &lt;/p&gt;  &lt;p&gt;As software books reviews site is about providing reviews for the books the main features that need to be covered by application are following. &lt;/p&gt;  &lt;p&gt;Visitor comes to the web site. From here he can navigate through existing books and read reviews and summaries. Review can be written on the site or link to the web site with the review can be provided. Summary is expressed as number (from 1 to 5) of some book aspects. Visitor can register and then he is able to post reviews and summaries for the books. Additionally there are some tasks for the administrator like: moderating books, posting new books...&lt;/p&gt;  &lt;p&gt;If I try to express this short description as a list of user stories we get following:&lt;/p&gt;  &lt;p&gt;As visitor I want to register.&lt;/p&gt;  &lt;p&gt;As registered user I want to login.&lt;/p&gt;  &lt;p&gt;As visitor I want to see books and reviews/summaries of the books.&lt;/p&gt;  &lt;p&gt;As registered user I want to post book review.&lt;/p&gt;  &lt;p&gt;As registered user I want to post summary.&lt;/p&gt;  &lt;p&gt;As administrator I want to moderate books (this is probably epic).&lt;/p&gt;  &lt;p&gt;Although user stories should be implemented one by one it is not a mistake to make an overview of the whole system. So described system can be pictured like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_qCynPb3bKW0/ShMqmnB7FDI/AAAAAAAABZg/EmFNKjlm3xM/s1600-h/domain_model%5B3%5D.jpg"&gt;&lt;img style="border: 0px none ;" alt="domain_model" src="http://lh3.ggpht.com/_qCynPb3bKW0/ShMqnELXhlI/AAAAAAAABZk/FN8ZTeVxUPk/domain_model_thumb%5B1%5D.jpg?imgmax=800" border="0" width="303" height="186" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On the picture above I have depicted domain object classes that I will create for the &lt;em&gt;sbr&lt;/em&gt; project. For those that already have some knowledge about GORM the class &lt;em&gt;BookAuthor&lt;/em&gt; may be surprising. In the GORM it is possible to model "many-to-many" relationship directly. I don't like this way and most of the time I create additional domain class that is representing connection object. Of course you can use what ever approach but for me this is much more flexible because I can easily navigate in both directions in the relationship and even having custom logical methods in the connecting class - BookAuthor in this case.&lt;/p&gt;  &lt;p&gt;Let me write few words about this domain objects model. As you can see the central place in the model plays the &lt;em&gt;Book&lt;/em&gt; class. It is not surprise because &lt;em&gt;sbr&lt;/em&gt; is more or less about books. For each book we want to have different details except reviews and summaries. Those details are &lt;em&gt;Author&lt;/em&gt; and &lt;em&gt;Publisher&lt;/em&gt;. &lt;/p&gt;  &lt;p&gt;The relationship between &lt;em&gt;Book&lt;/em&gt; and &lt;em&gt;Author&lt;/em&gt; is many-to-many. This means that each book can have more than one author and each author can write more than one book. Thus domain object &lt;em&gt;BookAuthor&lt;/em&gt; is created.&lt;/p&gt;  &lt;p&gt;The relationship between &lt;em&gt;Book&lt;/em&gt; and &lt;em&gt;Publisher&lt;/em&gt; is many-to-one. This means that each book can have only one publisher. Or from the other point of the relationship, each publisher can publish many books.&lt;/p&gt;  &lt;p&gt;Next interesting part of the diagram is &lt;em&gt;BookReview &lt;/em&gt;and &lt;em&gt;BookSummary&lt;/em&gt; and &lt;em&gt;User&lt;/em&gt;. The logic here is that book review and book summary must be provided for an existing book by an existing user. There is no limit on the domain level how many reviews/summaries user can provide for the same book. This limit is set as a business logic. Registered user can post one review/summary per book while moderator can post many reviews per book and one summary per book.&lt;/p&gt;  &lt;p&gt;Knowing all these we are ready to start with implementation. If you do it in hurry you can start with the book class. But as we already know that we will need possibility to register and we will need &lt;em&gt;User&lt;/em&gt; class it is good moment to have a look into grails plugins. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Before you start implementing anything in the Grails it is good idea to see what is available from the Grails plugins.&lt;/strong&gt; Very often functionality you need is already implemented as a plugin and you can simply reuse it. The same story is for registration and the &lt;em&gt;User&lt;/em&gt; class. For software books reviews site I am using Spring security plugin (former Acegi security plugin). So you need to install this plugin. How to do that you can find in the plugins section of the &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt; web site. After installing it create two roles: admin and user. This plugin offers out of the box login, logout, register pages and lot of useful methods that can be used in the application.&lt;/p&gt;  &lt;p&gt;So in my next post I will install Spring (Acegi) security plugin, initialize default roles on the startup (if they are not initialized already) and then we will include register/login links on the home page and implement the first two user stories: As visitor I want to register and As registered user I want to login. So stay tuned.&lt;/p&gt;  &lt;p&gt;P.S. Don't forget to write some review or post summary on the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-7090526925832699359?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/X1cUgMQLeRztIEzNk-0jOdIOUmc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/X1cUgMQLeRztIEzNk-0jOdIOUmc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/X1cUgMQLeRztIEzNk-0jOdIOUmc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/X1cUgMQLeRztIEzNk-0jOdIOUmc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=wz7d-4Lzdz4:bp0D5bMCmRA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=wz7d-4Lzdz4:bp0D5bMCmRA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=wz7d-4Lzdz4:bp0D5bMCmRA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=wz7d-4Lzdz4:bp0D5bMCmRA:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=wz7d-4Lzdz4:bp0D5bMCmRA:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=wz7d-4Lzdz4:bp0D5bMCmRA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=wz7d-4Lzdz4:bp0D5bMCmRA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=wz7d-4Lzdz4:bp0D5bMCmRA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=wz7d-4Lzdz4:bp0D5bMCmRA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=wz7d-4Lzdz4:bp0D5bMCmRA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/wz7d-4Lzdz4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/7090526925832699359/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=7090526925832699359" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/7090526925832699359?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/7090526925832699359?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/wz7d-4Lzdz4/analyzing-domain-of-problem-gorm.html" title="Analyzing domain of the problem - GORM classes" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/05/analyzing-domain-of-problem-gorm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQDSHk5fip7ImA9WxJSFUg.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-6080275719425310107</id><published>2009-05-05T22:43:00.002+02:00</published><updated>2009-05-05T22:46:19.726+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-05T22:46:19.726+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>Integrating blueprint into Grails application</title><content type="html">&lt;p&gt;&lt;strong&gt;[From the series - creating &lt;/strong&gt;&lt;a href="http://www.softwarebooksreviews.com/"&gt;&lt;strong&gt;software books reviews&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; grails web application]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In the previous post we have created &lt;a href="http://jan-so.blogspot.com/2009/04/creating-home-and-admin-page.html"&gt;home and admin page&lt;/a&gt;. Now it is time to create layout of the application. If you visit software books reviews site you can see that layout of the page is header and footer and three columns. If you are not a CSS expert creating such layout can be probably complex so it is good idea to use help of some CSS framework. My CSS framework is &lt;a href="http://www.blueprintcss.org/"&gt;blueprint&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Blueprint is the grid based framework with the fixed width. Screen is divided into 24 columns and you can specify &lt;em&gt;"boxes" &lt;/em&gt;and number of columns they should span through. The most important thing to remember is that sum of the box widths may not be bigger than 24. It can be smaller but not bigger.&lt;/p&gt;  &lt;p&gt;The short example of the web page with the blueprint can look like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="container"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="one"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-24 last"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="rem"&gt;&amp;lt;!-- some content --&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;hr&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="two"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-4 colborder"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="rem"&gt;&amp;lt;!-- some content --&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="three"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-14 colborder"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="rem"&gt;&amp;lt;!-- some content --&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-4 last"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;In this short code example the most important features of the blueprint framework are already visible.&lt;/p&gt;&lt;p&gt;The first div with class &lt;em&gt;container&lt;/em&gt; is mandatory and blueprint will work inside this div.&lt;/p&gt;&lt;p&gt;&lt;em&gt;&amp;lt;div id="one" class="span-24 last"&amp;gt;&lt;/em&gt; defines box that should spread through all 24 columns. This means that content will take the whole row of the screen. &lt;em&gt;"last"&lt;/em&gt; class is used to specified that it is last box in the given row. This class has more sense when the sum of box widths is less than 24 but you want to put next box into the new row.&lt;/p&gt;&lt;p&gt;&lt;em&gt;&amp;lt;hr&amp;gt;&lt;/em&gt; is blueprint tag that just makes more space between two rows.&lt;/p&gt;&lt;p&gt;Next three &lt;em&gt;&amp;lt;divs&lt;/em&gt;&amp;gt; are actually more interesting. Here you are defining that row should be divided into three columns. First column of the width 4, next column of the width 14, and last column of the width 4. What you can notice immediately is that sum of these numbers is 22. &lt;/p&gt;&lt;p&gt;The reason is that class &lt;em&gt;colborder&lt;/em&gt; separates two columns and actually takes the space of the whole column.&lt;/p&gt;&lt;p&gt;Now when we have basic knowledge about blueprint it is time to integrate it into our &lt;em&gt;sbr&lt;/em&gt; application. The first step is to download the blueprint framework from their site. When you extract the downloaded zip file, copy the three css files from the &lt;em&gt;blueprint&lt;/em&gt; folder. The file to copy are: ie.css, screen.css, and print.css. &lt;/p&gt;&lt;p&gt;You should copy them into &lt;em&gt;web-app/css&lt;/em&gt; folder of the &lt;em&gt;sbr&lt;/em&gt; application.&lt;/p&gt;&lt;p&gt;Now it is time to define layout of our application. As already mentioned we want that all pages are same and have header/footer and three columns: left, middle and right column. If you have read Starting with front-end in Grails application post then it should be clear that the right place where to specify this is the &lt;em&gt;main.gsp&lt;/em&gt; template. This template specifies how all pages that are based on this template will look like. First of all we need to reference css files we have copied to the &lt;em&gt;css&lt;/em&gt; folder. To do this change to &lt;em&gt;grails-app/views/layouts/main.gsp&lt;/em&gt; to look like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutTitle&lt;/span&gt; &lt;span class="attr"&gt;default&lt;/span&gt;&lt;span class="kwrd"&gt;="Grails"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'main.css')}"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutHead&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'screen.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="screen, projection"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'print.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="print"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'ie.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="screen, projection"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:javascript&lt;/span&gt; &lt;span class="attr"&gt;library&lt;/span&gt;&lt;span class="kwrd"&gt;="application"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;               &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutBody&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;       &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;The three lines to notice are:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'screen.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="screen, projection"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'print.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="print"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'ie.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="screen, projection"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;They are added as specified by the blueprint framework. The only difference is that I have used &lt;em&gt;createLinkTo&lt;/em&gt; grails construct. &lt;/p&gt;&lt;p&gt;Now when we are referencing necessary css files we can specify layout of the template.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutTitle&lt;/span&gt; &lt;span class="attr"&gt;default&lt;/span&gt;&lt;span class="kwrd"&gt;="Grails"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'main.css')}"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutHead&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'screen.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="screen, projection"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'print.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="print"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'ie.css')}"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt; &lt;span class="attr"&gt;media&lt;/span&gt;&lt;span class="kwrd"&gt;="screen, projection"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:javascript&lt;/span&gt; &lt;span class="attr"&gt;library&lt;/span&gt;&lt;span class="kwrd"&gt;="application"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="container"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="header"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-24 last"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;               header&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;hr&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="left-sidebar"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-4 colborder"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;               left sidebar&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="content"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-14 colborder"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;               &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutBody&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="right-sidebar"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-4 last"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;               right sidebar&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;hr&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="footer"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="span-24 last"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;               footer&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;As you can see that is quiet easy and understandable. And what is good it is all what we need to the to get required layout. If you start the application now you will see that home page of the &lt;em&gt;sbr&lt;/em&gt; application has correct layout. Of course we still need to populate all parts with the real content but that will be part of the next posts.&lt;/p&gt;&lt;p&gt;I know that usually I am announcing what will be topic of the next post but this time I am not sure. But for sure good reading is introduction into grails templates and tag libs mechanism that I have described in &lt;a href="http://jan-so.blogspot.com/2008/02/example-of-template-and-taglib-with.html"&gt;this&lt;/a&gt; and &lt;a href="http://jan-so.blogspot.com/2008/06/make-gsp-readable-with-grails-templates.html"&gt;this&lt;/a&gt; post.&lt;/p&gt;&lt;p&gt;P.S. Don't forget to write some review or post summary on the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-6080275719425310107?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/gOk9sxR4uo1KlRIURCczfNIUFfw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gOk9sxR4uo1KlRIURCczfNIUFfw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/gOk9sxR4uo1KlRIURCczfNIUFfw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/gOk9sxR4uo1KlRIURCczfNIUFfw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=vEKaXSuKtWs:NMplmsqypbI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=vEKaXSuKtWs:NMplmsqypbI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=vEKaXSuKtWs:NMplmsqypbI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=vEKaXSuKtWs:NMplmsqypbI:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=vEKaXSuKtWs:NMplmsqypbI:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=vEKaXSuKtWs:NMplmsqypbI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=vEKaXSuKtWs:NMplmsqypbI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=vEKaXSuKtWs:NMplmsqypbI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=vEKaXSuKtWs:NMplmsqypbI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=vEKaXSuKtWs:NMplmsqypbI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/vEKaXSuKtWs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/6080275719425310107/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=6080275719425310107" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/6080275719425310107?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/6080275719425310107?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/vEKaXSuKtWs/integrating-blueprint-into-grails.html" title="Integrating blueprint into Grails application" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/05/integrating-blueprint-into-grails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMFSH8yfSp7ImA9WxJTGUk.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-4367376187977051410</id><published>2009-04-28T01:16:00.002+02:00</published><updated>2009-04-28T21:53:39.195+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-28T21:53:39.195+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>Creating home and admin page</title><content type="html">&lt;p&gt;&lt;strong&gt;[From the series - creating &lt;/strong&gt;&lt;a href="http://www.softwarebooksreviews.com/"&gt;&lt;strong&gt;software books reviews&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; grails web application]&lt;/strong&gt; &lt;/p&gt;  &lt;p&gt;In the previous post I have explained some basic &lt;a href="http://jan-so.blogspot.com/2009/04/starting-with-front-end-in-grails.html"&gt;aspects of grails front-end&lt;/a&gt;. Having this knowledge it is a time to create home page of &lt;em&gt;sbr&lt;/em&gt; application. For the list of steps how I got up to this point you may want to have a look at this post &lt;a href="http://jan-so.blogspot.com/2009/04/series-from-developing-software-books.html"&gt;pointing to all posts related to sbr series&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;If you start &lt;em&gt;sbr&lt;/em&gt; application (&lt;em&gt;grails run-app&lt;/em&gt;) default home page generated by grails is displayed. This is not very useful page as a home page but will be very useful as admin page. It can be very useful as a admin page because it displays all controllers in your application. For each controller you can generate default list/show/create/edit pages.&lt;/p&gt;  &lt;p&gt;So let create home page. To create home page I usually create &lt;em&gt;HomeController&lt;/em&gt;. So the first step is to generate home controller.  To create home controller type the following command:&lt;/p&gt;  &lt;p&gt;&lt;em&gt;grails create-controller Home&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;This command will generate &lt;em&gt;HomeController.groovy&lt;/em&gt; file in the &lt;em&gt;grails-app/controllers&lt;/em&gt; folder and &lt;em&gt;home&lt;/em&gt; folder in the &lt;em&gt;grails-app/views&lt;/em&gt; folder. In this folder we should put our new home page.&lt;/p&gt;  &lt;p&gt;So to create home page in the &lt;em&gt;home&lt;/em&gt; folder create file &lt;em&gt;home.gsp&lt;/em&gt; that should look like this one:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;SBR&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;meta&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="layout"&lt;/span&gt; &lt;span class="attr"&gt;content&lt;/span&gt;&lt;span class="kwrd"&gt;="main"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       Welcome to the SBR&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;We want to display this page when ever the &lt;em&gt;HomeController&lt;/em&gt; is accessed. This is very easy to achieve. Update the code of the &lt;em&gt;HomeController&lt;/em&gt; to look like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; HomeController {&lt;br /&gt;   def index = {&lt;br /&gt;       render (view:&lt;span class="str"&gt;'home'&lt;/span&gt;)&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;&lt;em&gt;index&lt;/em&gt; closure is default closure of the controller and is executed when controller is accessed without specifying action to be executed. So if you type in your browser &lt;a href="http://localhost:8080/sbr/home"&gt;http://localhost:8080/sbr/home&lt;/a&gt;, index action will be executed. And this action is telling that the view '&lt;em&gt;home&lt;/em&gt;' should be displayed. As you are in the &lt;em&gt;HomeController&lt;/em&gt; it will look for the file &lt;em&gt;home.gsp&lt;/em&gt; in the &lt;em&gt;grails-app/views/home&lt;/em&gt; folder. But if you want in the &lt;em&gt;render&lt;/em&gt; closure you can specify the full path to the page to be displayed relative to the &lt;em&gt;views&lt;/em&gt; folder. So &lt;em&gt;render (view:'home/home')&lt;/em&gt; would be valid too.&lt;/p&gt;&lt;p&gt;Now it is time to create admin page. For admin page we will need &lt;em&gt;AdminController&lt;/em&gt;. To create &lt;em&gt;AdminController&lt;/em&gt; execute following command:&lt;/p&gt;&lt;p&gt;&lt;em&gt;grails create-controller admin&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Same as for the &lt;em&gt;HomeController&lt;/em&gt; this command will create file &lt;em&gt;AdminController.groovy&lt;/em&gt; and folder &lt;em&gt;admin&lt;/em&gt;. To create admin page in the &lt;em&gt;admin&lt;/em&gt; folder create &lt;em&gt;admin.gsp&lt;/em&gt; file. Copy the content of the &lt;em&gt;web-app/index.gsp&lt;/em&gt; file into the &lt;em&gt;admin.gsp&lt;/em&gt; file. At the end &lt;em&gt;admin.gsp&lt;/em&gt; should look like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;SBR admin&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;meta&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="layout"&lt;/span&gt; &lt;span class="attr"&gt;content&lt;/span&gt;&lt;span class="kwrd"&gt;="main"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="dialog"&lt;/span&gt; &lt;span class="attr"&gt;style&lt;/span&gt;&lt;span class="kwrd"&gt;="margin-left:20px;width:60%;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;             &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:each&lt;/span&gt; &lt;span class="attr"&gt;var&lt;/span&gt;&lt;span class="kwrd"&gt;="c"&lt;/span&gt; &lt;span class="attr"&gt;in&lt;/span&gt;&lt;span class="kwrd"&gt;="${grailsApplication.controllerClasses}"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="controller"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:link&lt;/span&gt; &lt;span class="attr"&gt;controller&lt;/span&gt;&lt;span class="kwrd"&gt;="${c.logicalPropertyName}"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;${c.fullName}&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;g:link&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;li&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;             &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;g:each&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;We still need ability to display admin page. To process is the same as for the &lt;em&gt;HomeController&lt;/em&gt;. Change the &lt;em&gt;AdminController&lt;/em&gt; so it looks like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; AdminController {&lt;br /&gt;   def index = {&lt;br /&gt;       render (view:&lt;span class="str"&gt;'admin'&lt;/span&gt;)&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;But still, when you start application and access the link &lt;a href="http://localhost:8080/sbr"&gt;http://localhost:8080/sbr&lt;/a&gt; you are getting old index page. To change this change the &lt;em&gt;web-app/index.gsp&lt;/em&gt; file to this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;response.sendRedirect(request.getContextPath()+&lt;span class="str"&gt;"/home/"&lt;/span&gt;);&lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;This will redirect you to the &lt;em&gt;HomeController&lt;/em&gt; and &lt;em&gt;home&lt;/em&gt; page will be displayed after accessing &lt;em&gt;sbr&lt;/em&gt; application.&lt;/p&gt;&lt;p&gt;We are almost done. But what is still remaining is to update template that we use for our pages. So go the the &lt;em&gt;grails-app/views/layouts/main.gsp&lt;/em&gt; file and change it to look like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutTitle&lt;/span&gt; &lt;span class="attr"&gt;default&lt;/span&gt;&lt;span class="kwrd"&gt;="Grails"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;link&lt;/span&gt; &lt;span class="attr"&gt;rel&lt;/span&gt;&lt;span class="kwrd"&gt;="stylesheet"&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="${createLinkTo(dir:'css',file:'main.css')}"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutHead&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:javascript&lt;/span&gt; &lt;span class="attr"&gt;library&lt;/span&gt;&lt;span class="kwrd"&gt;="application"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;               &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutBody&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;       &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;What I did are just simple changes to this file. Actually I have only removed some code from file generated by default.&lt;/p&gt;&lt;p&gt;As it turned out that this post is longer than I have expected let me summarize steps I have done. So after your grails application is generated you are ready to create home and future admin page. I am usually doing these steps:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Create &lt;em&gt;HomeController&lt;/em&gt; and &lt;em&gt;home.gps&lt;/em&gt; page &lt;/li&gt;  &lt;li&gt;Create &lt;em&gt;AdminController&lt;/em&gt; and &lt;em&gt;admin.gsp&lt;/em&gt; page &lt;/li&gt;  &lt;li&gt;Change &lt;em&gt;index.gsp&lt;/em&gt; file so it redirects to the &lt;em&gt;HomeController&lt;/em&gt; &lt;/li&gt;  &lt;li&gt;Make &lt;em&gt;main.gsp&lt;/em&gt; layout file simple. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;After those steps basic skeleton of the grails application is prepared.&lt;/p&gt;&lt;p&gt;What remains is to prepare layout of the &lt;em&gt;home.page&lt;/em&gt; and this can be achieved by changing &lt;em&gt;main.gsp&lt;/em&gt; file. If you remember from the previous post, &lt;em&gt;main.gsp&lt;/em&gt; is actually template that we can reuse for all the pages in the grails application. Actually we already did it for the &lt;em&gt;home&lt;/em&gt; and &lt;em&gt;admin&lt;/em&gt; page.&lt;/p&gt;&lt;p&gt;In the next post I will describe layouting of the &lt;em&gt;main&lt;/em&gt;.gsp&lt;em&gt; &lt;/em&gt;file or to be more precise I will integrate &lt;em&gt;blueprint css framework&lt;/em&gt; into &lt;em&gt;sbr&lt;/em&gt; application.&lt;/p&gt;&lt;p&gt;P.S. Don't forget to write some review or post summary on the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-4367376187977051410?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/c2NAlUpe5gErqK9Xta822yEuZAQ/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/c2NAlUpe5gErqK9Xta822yEuZAQ/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/c2NAlUpe5gErqK9Xta822yEuZAQ/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/c2NAlUpe5gErqK9Xta822yEuZAQ/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=5bg5BKZCrSc:3n3lMBNpk4c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=5bg5BKZCrSc:3n3lMBNpk4c:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=5bg5BKZCrSc:3n3lMBNpk4c:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=5bg5BKZCrSc:3n3lMBNpk4c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=5bg5BKZCrSc:3n3lMBNpk4c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=5bg5BKZCrSc:3n3lMBNpk4c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=5bg5BKZCrSc:3n3lMBNpk4c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=5bg5BKZCrSc:3n3lMBNpk4c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=5bg5BKZCrSc:3n3lMBNpk4c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=5bg5BKZCrSc:3n3lMBNpk4c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/5bg5BKZCrSc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/4367376187977051410/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=4367376187977051410" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4367376187977051410?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4367376187977051410?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/5bg5BKZCrSc/creating-home-and-admin-page.html" title="Creating home and admin page" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/04/creating-home-and-admin-page.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cHR3g6fyp7ImA9WxJTE0g.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-1280778699006460464</id><published>2009-04-21T23:53:00.002+02:00</published><updated>2009-04-21T23:57:16.617+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-21T23:57:16.617+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>Starting with front-end in grails application</title><content type="html">&lt;p&gt;&lt;strong&gt;[From the series - creating &lt;/strong&gt;&lt;a href="http://www.softwarebooksreviews.com/"&gt;&lt;strong&gt;software books reviews&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; grails web application]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In the previous post I have explained how to &lt;a href="http://jan-so.blogspot.com/2009/04/creating-grails-application.html"&gt;create grails application&lt;/a&gt; and some &lt;a href="http://jan-so.blogspot.com/2009/04/general-aspects-of-grails-application.html"&gt;general aspects&lt;/a&gt; of the grails application.  If you are expert for the web front-end you can probably jump into domain logic but if you are like me, front-end is probably harder part of the web application development. As it is generally advised to start with the more complex parts of the application I am usually setting up at least general aspects of the user interface. So let us see how is solved front-end of the grails application.&lt;/p&gt;  &lt;p&gt;View technology of the grails application is groovy server pages or shorter &lt;strong&gt;gsp&lt;/strong&gt; while sitemesh is used as main &lt;strong&gt;templating&lt;/strong&gt; mechanism. To gain knowledge of the existing gsp tags visit grails documentation. There is description and short example for each tag. If you don't know site mesh don't worry because I don't know it either. The main usage is very easy and does not require knowledge of the sitemesh.&lt;/p&gt;  &lt;p&gt;First interesting file to notice is &lt;em&gt;main.gsp&lt;/em&gt; that is located in the &lt;em&gt;grails-app/views/layouts&lt;/em&gt;. This file is template for other pages of the application. Just to notice, you can have any number of "main.gsp" files in your grails application. One for each different situation you need. E.g. one for pages with three columns, one for pages with two columns and so on.&lt;/p&gt;  &lt;p&gt;The most important part of the &lt;em&gt;main.gsp &lt;/em&gt;file is:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutBody&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;When some page as template uses &lt;em&gt;main.gsp&lt;/em&gt;, the whole content of the &lt;em&gt;main.gsp&lt;/em&gt; page will be displayed and the &lt;em&gt;&amp;lt;g:layoutBody /&amp;gt;&lt;/em&gt; will be replaced with the body element of the mentioned page. To specify which template should be used for the gsp page, put following construct in the &lt;em&gt;&amp;lt;head&amp;gt;&lt;/em&gt; element of the page.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;meta&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="layout"&lt;/span&gt; &lt;span class="attr"&gt;content&lt;/span&gt;&lt;span class="kwrd"&gt;="NAME_OF_TEMPLATE_FILE"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;and replace the NAME_OF_TEMPLATE_FILE with the name of template without &lt;em&gt;gsp&lt;/em&gt; extension.&lt;/p&gt;&lt;p&gt;So if you have page like this one:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;meta&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="layout"&lt;/span&gt; &lt;span class="attr"&gt;content&lt;/span&gt;&lt;span class="kwrd"&gt;="main"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;the &lt;em&gt;main.gsp&lt;/em&gt; will be displayed an the element &lt;em&gt;&amp;lt;g:layoutBody /&amp;gt; &lt;/em&gt;will be replaced with &lt;em&gt;&amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;&lt;/em&gt;. I am not sure that this is 100% correct but this is generally how it behaves. &lt;/p&gt;&lt;p&gt;If this is still confusing let try to make some simple example. Assume that we have two template files: &lt;em&gt;main1.gsp&lt;/em&gt; and &lt;em&gt;main2.gsp&lt;/em&gt; that are of course placed in the &lt;em&gt;grails-app/views/layouts&lt;/em&gt; directory.&lt;/p&gt;&lt;pre class="csharpcode"&gt;// main1.gsp&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutTitle&lt;/span&gt; &lt;span class="attr"&gt;default&lt;/span&gt;&lt;span class="kwrd"&gt;="Grails"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutHead&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutBody&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;       &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//main2.gsp&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutTitle&lt;/span&gt; &lt;span class="attr"&gt;default&lt;/span&gt;&lt;span class="kwrd"&gt;="Grails"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutHead&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;g:layoutBody&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;       &lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;h1&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;And if we create following two gsp pages&lt;/p&gt;&lt;pre class="csharpcode"&gt;// test1.gsp that uses main1.gsp as a template&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;meta&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="layout"&lt;/span&gt; &lt;span class="attr"&gt;content&lt;/span&gt;&lt;span class="kwrd"&gt;="main1"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Page 1&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;       &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// test2.gsp that uses main2.gsp as a template&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;meta&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="layout"&lt;/span&gt; &lt;span class="attr"&gt;content&lt;/span&gt;&lt;span class="kwrd"&gt;="main2"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Page 2&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;       &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;test1.gsp will be displayed as:&lt;/p&gt;&lt;pre class="csharpcode"&gt;Hello World&lt;br /&gt;Page 1&lt;/pre&gt;&lt;p&gt;while test2.gsp will be displayed as:&lt;/p&gt;&lt;pre class="csharpcode"&gt;Page 2&lt;br /&gt;Hello World&lt;/pre&gt;&lt;p&gt;This way you have very powerful tool to create set of pages that look the same and you are just changing the business content of the page. The "same" part should be located in the template file while the "business content" should be located in the page. If for some set of pages you need different layout just create new common template for them. All this magic is possible because grails in the background uses sitemesh for this.&lt;/p&gt;&lt;p&gt;Now when there is basic understanding how front-end works in the grails application we are ready to create our home page. And this will be topic of my next post. I will create dummy home page, admin page from the index.gsp and redirect application to the home page.&lt;/p&gt;&lt;p&gt;P.S. Don't forget to write some review or post summary on the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt;.&lt;/p&gt;&lt;style type="text/css"&gt;&lt;br /&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-1280778699006460464?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/JtDomvapDDuVdBOizIcQANvnKzs/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JtDomvapDDuVdBOizIcQANvnKzs/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/JtDomvapDDuVdBOizIcQANvnKzs/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/JtDomvapDDuVdBOizIcQANvnKzs/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Q0xX8gzCN7w:-n3zVLSD9P0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Q0xX8gzCN7w:-n3zVLSD9P0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Q0xX8gzCN7w:-n3zVLSD9P0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Q0xX8gzCN7w:-n3zVLSD9P0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Q0xX8gzCN7w:-n3zVLSD9P0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Q0xX8gzCN7w:-n3zVLSD9P0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Q0xX8gzCN7w:-n3zVLSD9P0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Q0xX8gzCN7w:-n3zVLSD9P0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=Q0xX8gzCN7w:-n3zVLSD9P0:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=Q0xX8gzCN7w:-n3zVLSD9P0:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/Q0xX8gzCN7w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/1280778699006460464/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=1280778699006460464" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/1280778699006460464?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/1280778699006460464?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/Q0xX8gzCN7w/starting-with-front-end-in-grails.html" title="Starting with front-end in grails application" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/04/starting-with-front-end-in-grails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcHQXc9eyp7ImA9WxNVGEU.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-4694597230166775259</id><published>2009-04-17T00:24:00.003+02:00</published><updated>2009-10-30T08:33:50.963+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-10-30T08:33:50.963+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>General Aspects of the Grails Application</title><content type="html">&lt;p&gt;&lt;strong&gt;[From the series - creating &lt;/strong&gt;&lt;a href="http://www.softwarebooksreviews.com/"&gt;&lt;strong&gt;software books reviews&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; grails web application]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In the previous post I have created empty "sbr" grails application. Before changing it to the real grails application it would be good to cover some basic aspects and communication flows of the more or less each grails application. This way it will be more clear what is happening. On the picture below I tried to write main aspects and communication flows of the grails application at least as I see them. I don't claim it is correct. If you need completely correct picture and definitions please refer to the Grails documentation.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_qCynPb3bKW0/SeewC2jyYUI/AAAAAAAABDE/h9ypTHww974/s1600-h/general_aspects_of_grails_applicatio%5B2%5D.jpg"&gt;&lt;img style="border-width: 0px;" alt="general_aspects_of_grails_application" src="http://lh3.ggpht.com/_qCynPb3bKW0/SeewDuhJolI/AAAAAAAABDI/xoYlIGBmK10/general_aspects_of_grails_applicatio%5B1%5D.jpg?imgmax=800" align="left" border="0" height="416" width="404" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Lets start from the top of the picture.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Probably as a first thing you want to display something to the end-user.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;GSP&lt;/strong&gt; stands for groovy server pages and is the view technology used in the grails. This means that front-end of the grails application is written in the GSP. To make GSP pages more readable and more scalable you can use &lt;strong&gt;TagLibs&lt;/strong&gt; and &lt;strong&gt;Templates&lt;/strong&gt;. As I like to write easily readable code, taglibs and templates are features of the grails that enables you to write readable GSP pages. &lt;/p&gt;  &lt;p&gt;As the input into the GSP page you send a &lt;strong&gt;model&lt;/strong&gt;. Just not to be confused, model is actually map of &lt;em&gt;[key,value]&lt;/em&gt; pairs where key is the string and the value can be instance of any groovy or java class available on the classpath. Important part to remember is that value can be instance of &lt;strong&gt;any&lt;/strong&gt; class - not only domain objects. I am making this clear because for the "long" time I was limiting data in the model to the instances of domain objects.&lt;/p&gt;  &lt;p&gt;So when you are displaying GSP page, you are using gsp tags, custom taglibs, and templates. Data to be displayed on the page is contained in the model. Example of the map representing model can &lt;em&gt;[bookToDisplay:book]&lt;/em&gt;. The &lt;em&gt;bookToDisplay&lt;/em&gt; is the key (can be any string) while the &lt;em&gt;book&lt;/em&gt; is instance of the groovy class. To e.g. display title of the book in the GSP page you would write &lt;em&gt;${bookToDisplay.title}&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Now when information is displayed there is big chance we want to send some data back to server and process it.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Controllers&lt;/strong&gt; are groovy classes stored in the &lt;em&gt;controllers&lt;/em&gt; folder. Each closure defined in the controller is considered as action and can be called from the GSP pages. So for example if you click the button on the GSP pages that is wired to some action in the controller, action in that controller will be called. Important thing to remember is that controllers are &lt;strong&gt;stateless&lt;/strong&gt;. Controllers have access to the domain objects and to the services. This means, no business logic should be contained in the controller. Controller should use business logic available in the domain objects and services.&lt;/p&gt;  &lt;p&gt;Data sent from the GSP page to the controller is available to the controller via &lt;strong&gt;params&lt;/strong&gt;. &lt;em&gt;params&lt;/em&gt; is actually variable containing all the request parameters. Thanks to the groovy it is injected into each controller so you have easy access to all request parameters. &lt;/p&gt;  &lt;p&gt;So for example, if you have input field with the name &lt;em&gt;bookTitle&lt;/em&gt;, content of the field is available to the controller via construct &lt;em&gt;params.bookTitle&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Now when we got down from the GSP to the controller and we have all necessary data available via params variable the rest is easy.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;From the controller class it is very easy to use &lt;strong&gt;domain objects and/or services&lt;/strong&gt;. And when you are on the level of the domain object or service you are working with normal groovy and/or java. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Services &lt;/strong&gt;are groovy classes stored within &lt;em&gt;services&lt;/em&gt; folder. Services provide transactional context for database operations and can by dynamically injected into controller and domain classes. Business logic that is not directly connected with concrete domain object should be put into service. Additionally you can use service to surround transactional behavior around multiple calls on the domain objects.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Domain Objects&lt;/strong&gt; represents domain of the problem you are solving. They are stored in the &lt;em&gt;domain&lt;/em&gt; folder. They are famous because they represent GORM classes, grails solution for persistence. Domain classes are mapped to the databases and the database is automatically generated or updated for you according to relationships between domain objects.&lt;/p&gt;  &lt;p&gt;And of course the whole grails framework is built on the top of the hibernate and spring. This ensures stability and scalability of the grails applications.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Summary&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;When you click on some button or link in the GSP page you are forwarded to the corresponding action in the controller. After performing basic validation in the controller you can use domain objects and services to perform application logic. After all necessary actions are performed you are creating model that is sent and displayed on the GSP page.&lt;/p&gt;  &lt;p&gt;In the next post I will return back to the "sbr" project. I will create home page and explain basic layouting options.&lt;/p&gt;  &lt;p&gt;P.S. Don't forget to write some review or post summary on the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-4694597230166775259?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/eQFvhRcuKAlS0KuH4TTO6oAOMVY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eQFvhRcuKAlS0KuH4TTO6oAOMVY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/eQFvhRcuKAlS0KuH4TTO6oAOMVY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/eQFvhRcuKAlS0KuH4TTO6oAOMVY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=csnVNKfajHA:ECKO-F0jM6Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=csnVNKfajHA:ECKO-F0jM6Y:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=csnVNKfajHA:ECKO-F0jM6Y:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=csnVNKfajHA:ECKO-F0jM6Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=csnVNKfajHA:ECKO-F0jM6Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=csnVNKfajHA:ECKO-F0jM6Y:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=csnVNKfajHA:ECKO-F0jM6Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=csnVNKfajHA:ECKO-F0jM6Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=csnVNKfajHA:ECKO-F0jM6Y:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=csnVNKfajHA:ECKO-F0jM6Y:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/csnVNKfajHA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/4694597230166775259/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=4694597230166775259" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4694597230166775259?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4694597230166775259?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/csnVNKfajHA/general-aspects-of-grails-application.html" title="General Aspects of the Grails Application" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/04/general-aspects-of-grails-application.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EMRno9eyp7ImA9WxVaEEg.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-3435612265210524839</id><published>2009-04-07T01:13:00.002+02:00</published><updated>2009-04-07T01:14:47.463+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-07T01:14:47.463+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="searchable" /><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><title>Eager fetching and searchable plugin in Grails</title><content type="html">&lt;p&gt;What came as surprise to me is that eager fetching even when specified on the level of the domain class does not work with the searchable plugin. I hit this problem while working on the software books reviews and statement and description why I found on one blog post. Unfortunately I cannot find the mentioned post again so I am not able to give a credit to the original author by linking to his/her post.&lt;/p&gt;  &lt;p&gt;So for example lets have Book domain class that among other properties has publisher property specified like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; Book {&lt;br /&gt;   &lt;span class="kwrd"&gt;static&lt;/span&gt; searchable = &lt;span class="kwrd"&gt;true&lt;/span&gt;&lt;br /&gt;   Publisher publisher&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;static&lt;/span&gt; fetchMode = [publisher:&lt;span class="str"&gt;"eager"&lt;/span&gt;]&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Using searchable plugin you can search for the books like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt; Map&amp;lt;String,String&amp;gt; options = &lt;span class="kwrd"&gt;new&lt;/span&gt; HashMap&amp;lt;String, String&amp;gt;()&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;params&lt;/span&gt;.offset) {&lt;br /&gt;       options.put(&lt;span class="str"&gt;'offset'&lt;/span&gt;,&lt;span class="kwrd"&gt;new&lt;/span&gt; Long(&lt;span class="kwrd"&gt;params&lt;/span&gt;.offset))&lt;br /&gt;}&lt;br /&gt;options.put(&lt;span class="str"&gt;'escape'&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;)&lt;br /&gt;options.put(&lt;span class="str"&gt;'max'&lt;/span&gt;,10)&lt;br /&gt;def searchResult = Book.search(&lt;span class="kwrd"&gt;params&lt;/span&gt;.searchTerm, options)&lt;/pre&gt;&lt;p&gt;After executing given query &lt;em&gt;searchResult.result&lt;/em&gt; will be populated with the list of found Book instances. And in this moment you hope that everything is fine. You send the found list of books to the view but to your surprise you see that publisher is not displayed for each of the book. You check if the book has publisher and it is in the database. The reason for the missing publisher is that the domain classes are created differently when loaded from the lucene index file.&lt;/p&gt;&lt;p&gt;To resolve this problem I have actually reloaded all the found books from the database. This way all the books are of course loaded as specified in the domain object. So code for searching looks like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;Map&amp;lt;String,String&amp;gt; options = &lt;span class="kwrd"&gt;new&lt;/span&gt; HashMap&amp;lt;String, String&amp;gt;()&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;params&lt;/span&gt;.offset) {&lt;br /&gt;   options.put(&lt;span class="str"&gt;'offset'&lt;/span&gt;,&lt;span class="kwrd"&gt;new&lt;/span&gt; Long(&lt;span class="kwrd"&gt;params&lt;/span&gt;.offset))&lt;br /&gt;}&lt;br /&gt;options.put(&lt;span class="str"&gt;'escape'&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;)&lt;br /&gt;options.put(&lt;span class="str"&gt;'max'&lt;/span&gt;,10)&lt;br /&gt;def searchResult = Book.search(&lt;span class="kwrd"&gt;params&lt;/span&gt;.searchTerm, options)&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// create new results because those current one are actually not loaded eagery&lt;/span&gt;&lt;br /&gt;def newResults = &lt;span class="kwrd"&gt;new&lt;/span&gt; ArrayList()&lt;br /&gt;searchResult.results.each {book -&amp;gt;&lt;br /&gt;   def bookToAdd = Book.get(book.id)&lt;br /&gt;   newResults.add(bookToAdd)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;searchResult.results = newResults&lt;/pre&gt;&lt;p&gt;So if you have integrated searching into your grails application and expects that some parts of the domain object are loaded eagerly you should probably use approach similar to this one.&lt;/p&gt;&lt;p&gt;P.S. Don't forget to write some review or post summary on the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-3435612265210524839?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/iqYLbwQPxny4Iq89ywz5Am6kTko/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iqYLbwQPxny4Iq89ywz5Am6kTko/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/iqYLbwQPxny4Iq89ywz5Am6kTko/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/iqYLbwQPxny4Iq89ywz5Am6kTko/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=1KPktmb-6Cg:SMHMe3vc_6c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=1KPktmb-6Cg:SMHMe3vc_6c:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=1KPktmb-6Cg:SMHMe3vc_6c:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=1KPktmb-6Cg:SMHMe3vc_6c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=1KPktmb-6Cg:SMHMe3vc_6c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=1KPktmb-6Cg:SMHMe3vc_6c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=1KPktmb-6Cg:SMHMe3vc_6c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=1KPktmb-6Cg:SMHMe3vc_6c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=1KPktmb-6Cg:SMHMe3vc_6c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=1KPktmb-6Cg:SMHMe3vc_6c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/1KPktmb-6Cg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/3435612265210524839/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=3435612265210524839" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/3435612265210524839?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/3435612265210524839?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/1KPktmb-6Cg/eager-fetching-and-searchable-plugin-in.html" title="Eager fetching and searchable plugin in Grails" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/04/eager-fetching-and-searchable-plugin-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEERno9cSp7ImA9WxVbGUo.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-7988760005431941876</id><published>2009-04-06T00:49:00.001+02:00</published><updated>2009-04-06T01:03:27.469+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-06T01:03:27.469+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>Creating Grails Application</title><content type="html">&lt;p&gt;&lt;strong&gt;[From the series - creating &lt;/strong&gt;&lt;a href="http://www.softwarebooksreviews.com/"&gt;&lt;strong&gt;software books reviews&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; grails web application]&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In this post just for the sake of completeness I will shortly describe how to create grails application. As in the series of the post I will more or less explain some aspects of programming in the Grails and partially recreate software books reviews site  the project to create I will call &lt;em&gt;sbr &lt;/em&gt;(short for software books reviews).&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; I am currently using Grails 1.0.3 version.&lt;/p&gt;  &lt;p&gt;Creating Grails application is very easy. Open some command line tool and execute the command:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;grails create-app sbr&lt;/pre&gt;&lt;p&gt;Now the folder named &lt;em&gt;sbr&lt;/em&gt; is create and in this folder is new grails application.&lt;/p&gt;&lt;p&gt;Actually you are already able to start this web application by executing following command from the &lt;em&gt;sbr&lt;/em&gt; folder:&lt;/p&gt;&lt;pre class="csharpcode"&gt;grails run-app&lt;/pre&gt;&lt;p&gt;To access the application in the browser enter: &lt;em&gt;&lt;a href="http://localhost:8080/sbr"&gt;http://localhost:8080/sbr&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;In the case you want to start application on another port you can do that using following command:&lt;/p&gt;&lt;pre class="csharpcode"&gt;grails -Dserver.port=[port_number] run-app&lt;/pre&gt;&lt;p&gt;And of course instead of the &lt;em&gt;[port_number]&lt;/em&gt; you should enter number of the port on which you want to start web application. &lt;/p&gt;&lt;p&gt;When Grails application is started this way without any changes it is run using embedded Jetty web container and in-memory HSQLDB that is default Grails configuration. Later on I will explain how to change database and how to deploy to Tomcat.&lt;/p&gt;&lt;p&gt;Let me shortly explain folders of the grails application. The top level folders are displayed on the following screen shot:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_qCynPb3bKW0/SdkyxyRUehI/AAAAAAAABCE/tPZUR-vN4CU/s1600-h/grails_folder%5B2%5D.png"&gt;&lt;img style="border-width: 0px;" alt="grails_folder" src="http://lh3.ggpht.com/_qCynPb3bKW0/Sdkyy4LiQjI/AAAAAAAABCI/OkihoAj-lKI/grails_folder_thumb.png?imgmax=800" border="0" width="157" height="218" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Short explanation of generated folders is:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;grails-app actually contains the main part of the grails application and will be explained separately &lt;/li&gt;  &lt;li&gt;lib - contains all external dependencies to other java libraries and is by default empty &lt;/li&gt;  &lt;li&gt;scripts - contains scripts and is by default empty &lt;/li&gt;  &lt;li&gt;src - contains java and groovy source files and is by default empty &lt;/li&gt;  &lt;li&gt;test - contains unit and integration tests and is by default empty &lt;/li&gt;  &lt;li&gt;web-app - contains web application &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The content of the &lt;em&gt;grails-app&lt;/em&gt; folder is much more interesting because it contains the heart of your web application.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_qCynPb3bKW0/SdkyzNNO5cI/AAAAAAAABCM/oldTzETYI2g/s1600-h/grails_app_folder%5B2%5D.png"&gt;&lt;img style="border-width: 0px;" alt="grails_app_folder" src="http://lh3.ggpht.com/_qCynPb3bKW0/Sdkyz6x2yGI/AAAAAAAABCQ/NxWcHCaVx0M/grails_app_folder_thumb.png?imgmax=800" border="0" width="122" height="140" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;Names of the folders should be self descriptive enough but shortly:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;conf - contains configuration of the application. From this folder you are able to configure different aspects of the grails application like: datasources, hibernate, spring, bootstrap and so on. In the later post I will explain at least some of those files. &lt;/li&gt;  &lt;li&gt;controllers - contains controllers of the web application. Controllers are accessed from the views and of course represents C of the MVC pattern &lt;/li&gt;  &lt;li&gt;domain - is folder that will contain all application domain objects. All application domain objects are persisted while the database schema is automatically generated using hibernate. All domain objects are thanks to Groovy by default enriched with number of useful methods. &lt;/li&gt;  &lt;li&gt;i18n - is folder used to localized application &lt;/li&gt;  &lt;li&gt;services - are different services that can be used by controllers or domain objects. They are automatically initialized and inserted using spring. They also provide transactional behavior. &lt;/li&gt;  &lt;li&gt;taglib - folder that will contain custom tag libraries. Tag libraries are excellent feature of the grails that enables you to modularize front-end of the grails application. I am using them heavily. &lt;/li&gt;  &lt;li&gt;views - is the folder that contains html and gsp files of the application. In the one word it contains "pages" of the web application. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;And although not directly visible in the folder list, another important part for modularizing front-end of the grails application are templates. I will explain how templates can be used in the later posts.&lt;/p&gt;&lt;p&gt;In the next post I will shortly explain general aspects of the grails application, or namely all folders of the &lt;em&gt;grails-app&lt;/em&gt; folder. So stay tuned :)&lt;/p&gt;&lt;p&gt;P.S. Don't forget to write some review or post summary on the &lt;a href="http://www.softwarebooksreviews.com"&gt;software books reviews&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-7988760005431941876?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/91vB6n3-XV_BL3PfbhvHhcGU8V8/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/91vB6n3-XV_BL3PfbhvHhcGU8V8/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/91vB6n3-XV_BL3PfbhvHhcGU8V8/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/91vB6n3-XV_BL3PfbhvHhcGU8V8/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=gIgrE_CYLGw:4mjhVxFSCCo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=gIgrE_CYLGw:4mjhVxFSCCo:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=gIgrE_CYLGw:4mjhVxFSCCo:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=gIgrE_CYLGw:4mjhVxFSCCo:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=gIgrE_CYLGw:4mjhVxFSCCo:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=gIgrE_CYLGw:4mjhVxFSCCo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=gIgrE_CYLGw:4mjhVxFSCCo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=gIgrE_CYLGw:4mjhVxFSCCo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=gIgrE_CYLGw:4mjhVxFSCCo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=gIgrE_CYLGw:4mjhVxFSCCo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/gIgrE_CYLGw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/7988760005431941876/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=7988760005431941876" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/7988760005431941876?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/7988760005431941876?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/gIgrE_CYLGw/creating-grails-application.html" title="Creating Grails Application" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/04/creating-grails-application.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkICRHg8eyp7ImA9WxJRF0o.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-342962254591601328</id><published>2009-04-06T00:41:00.009+02:00</published><updated>2009-05-20T00:02:45.673+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-20T00:02:45.673+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>Series from the Developing Software Books Reviews</title><content type="html">As I have already promised few days ago, I will write a number of posts explaining my experience gained during development of the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt; and partially &lt;a href="http://www.grailstutorials.com/"&gt;grails tutorials&lt;/a&gt; site. Actually during the series of the posts I will more or less recreate software books reviews grails application. Just for the convenience, I will regularly update this post so it points to all posts from this series. So if you will like those posts come and visit this post from time to time.&lt;br /&gt;&lt;br /&gt;So the list of the posts so far is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://jan-so.blogspot.com/2009/04/developing-web-applications-with-grails.html"&gt;Developing Web Applications with Grails&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jan-so.blogspot.com/2009/04/creating-grails-application.html"&gt;Creating Grails Application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jan-so.blogspot.com/2009/04/general-aspects-of-grails-application.html"&gt;General Aspects of the Grails Application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jan-so.blogspot.com/2009/04/starting-with-front-end-in-grails.html"&gt;Starting with front-end in grails application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jan-so.blogspot.com/2009/04/creating-home-and-admin-page.html"&gt;Creating home and admin page&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jan-so.blogspot.com/2009/05/integrating-blueprint-into-grails.html"&gt;Integrating blueprint into Grails application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://jan-so.blogspot.com/2009/05/analyzing-domain-of-problem-gorm.html"&gt;Analyzing domain of the problem - GORM classes&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-342962254591601328?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/inoCHMMMxRYsq1_r8AqX1N9YBvk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/inoCHMMMxRYsq1_r8AqX1N9YBvk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/inoCHMMMxRYsq1_r8AqX1N9YBvk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/inoCHMMMxRYsq1_r8AqX1N9YBvk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iBhJ-428ltw:-zqj36ri3Vw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iBhJ-428ltw:-zqj36ri3Vw:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iBhJ-428ltw:-zqj36ri3Vw:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iBhJ-428ltw:-zqj36ri3Vw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iBhJ-428ltw:-zqj36ri3Vw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iBhJ-428ltw:-zqj36ri3Vw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iBhJ-428ltw:-zqj36ri3Vw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iBhJ-428ltw:-zqj36ri3Vw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=iBhJ-428ltw:-zqj36ri3Vw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=iBhJ-428ltw:-zqj36ri3Vw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/iBhJ-428ltw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/342962254591601328/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=342962254591601328" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/342962254591601328?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/342962254591601328?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/iBhJ-428ltw/series-from-developing-software-books.html" title="Series from the Developing Software Books Reviews" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/04/series-from-developing-software-books.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE8HR387fyp7ImA9WxVbF0w.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-5702131842896729465</id><published>2009-04-03T00:53:00.001+02:00</published><updated>2009-04-03T00:53:56.107+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-03T00:53:56.107+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails" /><category scheme="http://www.blogger.com/atom/ns#" term="software books reviews" /><title>Developing Web Applications with Grails</title><content type="html">&lt;p&gt;As I have recently released &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt; I believe I have finally improved my skills also when working with pure front end (html, css) of web application. As I also mentioned in the &lt;a href="http://jan-so.blogspot.com/2009/03/have-you-recently-read-software-related.html"&gt;previous post&lt;/a&gt;, I plan to write series of posts explaining development work on the 'software books reviews' site. I hope my experience will be useful for additional developers. As I am coming from back-end Java development, while developing my first Grails applications the hardest part for me was HTML, css, layout... I believe posts I will write will also help other back-end developers to write web sites using Grails.&lt;/p&gt;  &lt;p&gt;I plan to write at least one post per week (till there is enough to write). I do not plan to cover basics like how to install grails or how to generate applications. There are already lot of articles covering these topics. But I hope posts will be clear enough so even beginners will be able to understand them.&lt;/p&gt;  &lt;p&gt;Lets go to the first topic :) &lt;/p&gt;  &lt;p&gt;So if you are reading this probably you want to write web applications using Grails. Let us see what topics one needs to cover to write web application:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;It is necessary to create nice front-end (HTML, css styles, layouts)&amp;#160; (disclaimer: I don't claim that I am making nice front-ends :) )&lt;/li&gt;    &lt;li&gt;It is necessary to implement business logic - behavior of the application&lt;/li&gt;    &lt;li&gt;Probably it is necessary to include security into application&lt;/li&gt;    &lt;li&gt;It is necessary to store data into database&lt;/li&gt;    &lt;li&gt;And very often it is necessary to provide some additional features that are not directly connected with business logic but in these days are more or less &amp;quot;must have&amp;quot;. Obvious feature are RSS feeds.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Grails can help us with most of these requirements while hiding most of the complexity from us. Thanks to grails the most complex things are hidden from us but we still have access to them.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Domain objects&lt;/strong&gt; - domain objects of course describe domain of our business logic. They are automatically persisted and loaded from the database. This means that database schema generation is something we don't need to think about most of the time.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Services&lt;/strong&gt; - provide functionality that is not part of the domain objects. In services you include functions that are not naturally fitting into domain objects. Further on services handle transactional behavior for you. You can configure them with simple flag. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Plugins&lt;/strong&gt; - Grails has excellent system of plugins. As we don't want to reinvent wheel we can reuse what is already implemented for us. Plugins will provide us with security, nice front-end components, RSS generation....&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Sitemesh&lt;/strong&gt; - is decorator engine supported by Grails to support view layouts. I am using it only on the basic level but even in such scenario it is very useful.&lt;/p&gt;  &lt;p&gt;So these are some basics that will help us to make developing web application fun and fast.&amp;#160; Using those features we will go through example implementation of the software books reviews.&lt;/p&gt;  &lt;p&gt;In the next post I will describe how I start project, and at least what are my basic first steps. I don't claim that it is the correct way but for me it turned out to be good. &lt;/p&gt;  &lt;p&gt;&lt;em&gt;Some advertisement:&lt;/em&gt; if you are reading software related books please be so kind to post review or link to review on the &lt;a href="http://www.softwarebooksreviews.com/"&gt;software books reviews&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-5702131842896729465?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/xzoyQD1NiMDpDifeuonqDmgTOtY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xzoyQD1NiMDpDifeuonqDmgTOtY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/xzoyQD1NiMDpDifeuonqDmgTOtY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/xzoyQD1NiMDpDifeuonqDmgTOtY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=NBue8MMcTac:N-C78kNC3lQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=NBue8MMcTac:N-C78kNC3lQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=NBue8MMcTac:N-C78kNC3lQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=NBue8MMcTac:N-C78kNC3lQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=NBue8MMcTac:N-C78kNC3lQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=NBue8MMcTac:N-C78kNC3lQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=NBue8MMcTac:N-C78kNC3lQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=NBue8MMcTac:N-C78kNC3lQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=NBue8MMcTac:N-C78kNC3lQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=NBue8MMcTac:N-C78kNC3lQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/NBue8MMcTac" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/5702131842896729465/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=5702131842896729465" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/5702131842896729465?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/5702131842896729465?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/NBue8MMcTac/developing-web-applications-with-grails.html" title="Developing Web Applications with Grails" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/04/developing-web-applications-with-grails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU8GRXcyfCp7ImA9WxVbFkw.&quot;"><id>tag:blogger.com,1999:blog-785059744103848185.post-4346598081871168668</id><published>2009-03-24T22:38:00.004+01:00</published><updated>2009-04-01T22:30:24.994+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-01T22:30:24.994+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="grails book review" /><title>Have you recently read a software related book?</title><content type="html">As number of other software developers I like to read books about software development too. Books I like to read are about general aspects of programming and about agile software development. As my latest free time burner is grails framework I put together these two passions and created web site &lt;a href="http://www.softwarebooksreviews.com/"&gt;Software Book Reviews&lt;/a&gt; of course using grails.&lt;br /&gt;The web site is devoted to software related books. You can provide review directly on the site or link to an existing review on the Internet. Further on you can also provide summary of the book by providing answers to three short and easy questions.&lt;br /&gt;&lt;br /&gt;As I like this web site and used little bit different approach than used for &lt;a href="http://www.grailstutorials.com/"&gt;Grails Tutorials &lt;/a&gt;I plan that some post about about my adventures developing software books reviews will come soon.&lt;br /&gt;&lt;br /&gt;In the meantime, if you have recently read some software related book maybe you can be so kind to post review on the site.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/785059744103848185-4346598081871168668?l=jan-so.blogspot.com'/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/kiKs2UrFkVl4slpilOoyxAD82uI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kiKs2UrFkVl4slpilOoyxAD82uI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/kiKs2UrFkVl4slpilOoyxAD82uI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kiKs2UrFkVl4slpilOoyxAD82uI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=cHEaEyEgCJE:AboUx0U3qp8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=cHEaEyEgCJE:AboUx0U3qp8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=cHEaEyEgCJE:AboUx0U3qp8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=cHEaEyEgCJE:AboUx0U3qp8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=cHEaEyEgCJE:AboUx0U3qp8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=cHEaEyEgCJE:AboUx0U3qp8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=cHEaEyEgCJE:AboUx0U3qp8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=cHEaEyEgCJE:AboUx0U3qp8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/jan-so?a=cHEaEyEgCJE:AboUx0U3qp8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/jan-so?i=cHEaEyEgCJE:AboUx0U3qp8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/jan-so/~4/cHEaEyEgCJE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://jan-so.blogspot.com/feeds/4346598081871168668/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=785059744103848185&amp;postID=4346598081871168668" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4346598081871168668?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/785059744103848185/posts/default/4346598081871168668?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/jan-so/~3/cHEaEyEgCJE/have-you-recently-read-software-related.html" title="Have you recently read a software related book?" /><author><name>jan</name><uri>http://www.blogger.com/profile/09450549833036134264</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06539389422217721686" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://jan-so.blogspot.com/2009/03/have-you-recently-read-software-related.html</feedburner:origLink></entry></feed>
