Archive for the ‘Tutorial’ Category

Playing with Grails application configuration

This small tutorial will show how to create a configuration file and how to manage configuration of your Grails application. It will show how to

  • Access configuration parameters
  • Create external configuration
  • Configure Spring for different environments
  • Create a new environment

Accessing configuration parameters

The configuration of Grails is stored in grails-app/conf directory. Parameters are stored in configuration files in “plain text way”

app.default.user = "tester"

or in “structured way”

app{
	default{
		user = "tester"
	}
}

In an application, one can access the parameters easily. Just import the correct class and ask it the correct question.

import org.codehaus.groovy.grails.commons.ConfigurationHolder
 
class TestController {
	def query = {
		render ConfigurationHolder.config.app.default.user
	}
}

The example above should render the string “tester”. Moreover, in the configuration files, one can easily define distinct config values for each of three different environments – production, development and test.

environments {
	production {
		grails.serverURL = "http://www.changeme.com"
	}
	development {
		grails.serverURL = "http://www.do-not-change.cz"
	}
	test {
		grails.serverURL = "http://www.just-for-test.de"
	}
}

External configuration

The configuration mechanism of Grails is nice, but there is a small trouble. The configuration files are compiled and packed into the deployment package (WAR) during project build phase. However, one usually does not want to rebuild the whole application just to change say a database password. So, how to do it?

The first step is to create an external configuration file. Let’s name it externalConfig.groovy. Its structure will be the same as the structure of the other configuration files – “flat text” or “structured”.

Now, how do you tell Grails to find and use it? Adding the following code to the beginning of your config.groovy will do the trick. It expects that there is an OS environment variable MY_GREAT_CONFIG that points to the configuration file.

if(System.getenv("MY_GREAT_CONFIG")) {
	println( "Including configuration file: " + System.getenv("MY_GREAT_CONFIG"));
	grails.config.locations << "file:" + System.getenv("MY_GREAT_CONFIG")
} else {
	println "No external configuration file defined."
}

Spring configuration

The grails-app/conf/spring/resources.groovy file gives the developer a convenient way to define beans. Distinguishing environments is slightly more complex than in other configuration files, but still elegant.

switch(GrailsUtil.environment) {
	case "production":
		myBean(package.BeanClass, 1, "prod")
		break
	case "test":
		myBean(package.BeanClass, 1, "test")
		break
	case "development":
		myBean(package.BeanClass, 1, "dev")
		break

Configuration parameters can be used here the same way as in the controller example above.

myBean(package.BeanClass, 1, ConfigurationHolder.config.app.default.user)

Adding more environments

It might seem that the development, test and production environments are just enough. Yes, that is true for most basic scenarios. However, if you develop for a large company with sophisticated deployment procedures, there are typically several production-level application server environments (one for user acceptance testing, one for system patch analysis and performance testing, one for production etc.), all of them corresponding to the Grails “production” environment.

How to address this scenario? Easily. Just introduce another environment into your configuration

environments {
	production {
		grails.serverURL = "http://www.changeme.com"
	}
	development {
		grails.serverURL = "http://www.do-not-change.cz"
	}
	test {
		grails.serverURL = "http://www.just-for-test.cz"
	}
	uat {
		grails.serverURL = "http://www.uat-testing-environment.cz"
	}
}

and run the application or create a war file with an extra parameter

	grails -Dgrails.env=uat war
	or
	grails -Dgrails.env=uat run-app

Modalbox in Grails

There is a nice and handy javascript library for creating kind of a modal “window”, similar to the famous lightbox. Here are few lines of code to make it running in a Grails application

Installation

First of all, you have to download the library. The easiest way is to install a plugin modalbox

grails install-plugin modalbox

There was a slight problem in version 0.2. So, check your plugins/modalbox-0.2/grails-app/taglib/ModalboxTagLib.groovy. The version was not correct and the script tags were not correctly ended. Here is my tag library.

class ModalboxTagLib {
 
    static namespace = "modalbox"
 
    def createLink = { attrs,body ->
        // By default trigger onclick, but allow onmouseover etc
        def event = attrs.event ? attrs.event : 'onclick';
 
        // linkname only supported for backwards-compatibility. Default it to empty-string
        def linkname = attrs.linkname ? attrs.linkname : ""
 
        out << """
            <a href='${g.createLink(attrs)}' title='${attrs['title']}' ${event}='Modalbox.show(this.href, {title: this.title, width: ${attrs['width']}}); return false;'>${linkname}${body.call()}</a>
        """
    }
 
    def modalIncludes = {
        def jsFolder    = createLinkTo(dir:'plugins',file:'modalbox-0.2/js/modalbox')
        def cssFolder   = createLinkTo(dir:'plugins',file:'modalbox-0.2/css')
 
        out << """
            <script type='text/javascript' src='${jsFolder}/prototype.js' ></script>
    		<script type='text/javascript' src='${jsFolder}/scriptaculous.js?load=effects'></script>
    		<script type='text/javascript' src='${jsFolder}/modalbox.js' ></script>
    		<link rel='stylesheet' href='${cssFolder}/modalbox.css' />
        """
    }
}

“Parent” view

In the view that will call the Modalbox, use tag modalInclude like this one.

<modalbox:createLink controller="book" action="showDetails" params="[bookId:book.id]" title="Book details" width="500">book</modalbox:createLink>

Once clicked, it calls book/showDetails

“Modalbox” view

The view of book/showDetails is quite simple. You can create any static page and it will be displayed. If you want something more “spicy”, use AJAX.

Book details
 
<g:formRemote name="myForm" url="[controller:'book',action:'findSimilar']" update="[success:'similar']" onComplete="Modalbox.resizeToContent()">
	<input type="hidden" name="bookId" value="${book.id}" />
	<input id='search' name='search' />
	<input type="submit" value="Find similar" />
</g:formRemote >
 
<div id="similar">
</div>
 
<a href="#" title="Close window" onclick="Modalbox.hide(); return false;">Close</a>

Notice the resizeToContent() method. It assures, that the content that will come via AJAX will fit. Last, but not least; for comfortable close, there is the last line.

Enjoy it.

Live fulltext search in Ruby on Rails

Some time ago I promised to create a small tutorial about live fulltext search. A fulltext search, that gives you results as you type.

Ingredients:

  • Ruby on rails
  • ferret gem (gem install ferret)
  • acts_as_ferret gem (gem install acts_as_ferret)
  • auto_complete plugin (from the application root: ruby script/plugin install auto_complete)

What we will do

  1. Create an empty application – simple book database
  2. Add fulltext search capabilities
  3. Create the live search
    1. Create search pane partial – the one that will display the search box
    2. Create the search results partial – that will render the hints (search results)
    3. Modify controller to respond to the search pane

Create a book database application

We will create a small application for book management. It will store, list, update books and it will also provide the live search.
So, lets create the skeleton of the aplication:

# Create the rails application
rails books
# create database books
echo "create database books"  | mysql -u root -p
cd books

Configure database login and password in app/config/database.yml.

development:
  adapter: mysql
  database: books
  username: root
  password: password
  host: localhost
  port: 3306

Create skeleton of the application. From root of the application run:

ruby script/generate scaffold Book title:string abstract:text

Create the books table

rake db:migrate

Start up the development server

ruby script/server

Now, browse to http://127.0.0.1:3000/books and type in some data.

Add fulltext search capabilities

Change the app/models/book.rb to support fulltext search

require "acts_as_ferret"
 
class Book < ActiveRecord::Base
    acts_as_ferret
end

You can check in the console, that the fulltext is enabled. Just start the console via
ruby script/console and put there

Book.find_by_contents("book").

It should return a result set, similar to this:

=> #<ActsAsFerret::SearchResults:0x2540f54 @results=[#<Book id: 2, title: "Book secondo", abstract: "Book about book", created_at: "2008-07-07 23:16:38", updated_at: "2008-07-07 23:16:38">, #<Book id: 1, title: "First book", abstract: "This is a first book", created_at: "2008-07-07 23:16:23", updated_at: "2008-07-07 23:16:23">], @total_hits=2>

Create the live search

Finally, create the live search.

Create search pane partial

The search_pane will be used to display search box.

Create a partial _search_pane.html.erb in app/views/books and put there simple tag. The tag create Ajax Autocompleter that calls auto_complete_for_search_query method of the default controller (in our case it will be books)

<%= text_field_with_auto_complete :search, :query %>

Add javascript include and partial rendering to the books template app/views/layouts/books.html.erb.

Do not forget! The javascript include must be in the head of the template.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title>Books: <%= controller.action_name %></title>
  <!-- HERE -->
  <%= stylesheet_link_tag 'scaffold' %>
	<%= javascript_include_tag :defaults %> 
</head>
<body>
 
<!-- AND HERE -->
<%= render :partial=>"books/search_pane" %>
 
<p style="color: green"><%= flash[:notice] %></p>
 
<%= yield  %>
 
</body>
</html>

Create the search results partial

The search_results will format the results of the full text search and will “offer” the resulting records. Create a partial app/views/books/_search_results.html.erb and add there the formatting code:

<ul>
	<% for book in @books %>
	<li><%= link_to h(book.title), :controller=>"books", :action=>"show", :id=>book %></li>
  	<% end %>
</ul>

Modify controller

Add the following line at the beginning of the books_controller.

protect_from_forgery :only => [:create, :update, :destroy]

Create a method in books_controller that will search for the books

 def auto_complete_for_search_query
   @books = Book.find_by_contents(params["search"]["query"]+"*", {:limit => 5})
   render :partial => "search_results"
 end

We do not want to generate the whole page layout, so it is necessary to specify it in the books controller:

layout 'books', :except => [:auto_complete_for_search_query]

And now, navigate to http://127.0.0.1:3000/books and start searching. As soon as you start typing into the search box, it shows results. Click on one of the proposed links to see what happens. Source code is here.