

Published on 2008-3-19 0:05:00 by Roman Mackovcak
The comparison will be written in a simple "table based" structure. I just got used to it when preparing comparisons or product studies for tenders.
Ruby on Rails
A lightweight web framework written in Ruby scripting programming language. It contains its own application server. See the Rails home website.Grails
A web framework written in Groovy. The source code is compiled to byte code and can be run on Java application servers. Grails home website.Maturity
Before I start comparison, it is fair to say, that Rails has been around from 2004 while Grails final version dates from 2008. So, some of the differences are caused by this time shift.Both of the frameworks are more evolutionary than revolutionary. They just implement the right patterns and they do it right.
| Ruby on Rails | Grails | |
|---|---|---|
| First release (version 1.0) | July 2004 | February 2008 |
| Life cycle | Mature framework with solid base of developers | Young framework with a growing base of developers and a huge base of potential developers (from Java) |
Documentation
| Ruby on Rails | Grails | |
|---|---|---|
| Framework | Excellent. Uses the RDoc that contains not only list of methods, classes and files, but also source code of a method, with syntax highlighting. | Very good. Contains list of classes, methods, files... but I am really missing the source code. If the code is not documented, the documentation is useless |
| Application | Excellent. Only the application files are documented using the RDoc (including syntax highlighting) | On one hand it is exhaustive, because it generates documentation for all classes in the project (including plugins). On the other hand it does not contain the source code. So, once the code is not documented, the documentation is useless. So, on average I would say it is good. |
Development
Both frameworks are based on flexible languages that allow meta programming - changing classes on the fly.| Ruby on Rails | Grails | ||
|---|---|---|---|
| Developer audience | From beginners | Some experience is required | |
| Language constructs | Readable, sometimes like natural language | Readable, sometimes too many brackets (but as I said, I spent some time in Ruby :o) | |
| Mapping objects to database | Excellent, all declarative | Excellent, all declarative | |
| Libraries | Wide variety of libraries and plugins. Almost everything I needed was available (except for Kerberos support...) | Huge amount of java libraries could be used together with Grails. This is one of Grails killer features. | |
| Scaffold | The default scaffold looks terrible, custom plugins needs to be installed. | Looks nice out of the box, implements handy nice features like table sorting. | |
| Tools | rake (~make), rjs (ruby java script - library that allows to write java script functionality in ruby), migrations (tool that uses ruby syntax to change database schema - very useful) | ant (~make) | |
| Log file | Very descriptive, it provides exactly the information needed: controller/action/parameters, time spent on DB, VIEW, CONTROLLER, SQL statements (including timing) | Verbose... very. Exception generated 1000 lines of code in log, missing the information about SQL statements and the things that are in the Rails log. This was a disappointment. | |
| Console | Simple terminal window working in command/result mode | Window based - command answer is displayed in different frame at the end of it (unfortunately it is not scrolling properly, so it is quite annoying). I take it as a temporary problem. | |
| Folder structure | Simple, follows the MVC | Following MVC, slightly more complex than RoR | |
| Thread support | Poor | Native |
Production
| Ruby on Rails | Grails | |
|---|---|---|
| Resource usage | Medium resource usage | Higher resource usage |
Potential
| Ruby on Rails | Grails | |
|---|---|---|
| Internet | High potential. The framework allows fast development of an application with a very good performance. | High potential. It alows fast development and it can utilize all of the Java frameworks. |
| Enterprises | Just for prototyping or small applications. The support of enterprise technologies is not at the focus of the community. | Could be used for prototyping and also for real applications |
There are many more differences that were not mentioned here. If you find a major one not mentioned here, please leave me a comment. I will appreciate it.

Published on 2008-3-11 17:39:00 by Roman Mackovcak
This is just a simple procedure how to tell subversion to ignore files or directories.
cd parent_directory
# Check the current setup
svn proplist -v .
# set the editor to edit the properties
export EDITOR=vi
# open up editor with the properties
svn propedit svn:ignore .
docs
*.log svn commit 
Published on 2008-3-10 22:15:00 by Roman Mackovcak
I managed to convert my family to Linux. Not intentionally, it just happened. The final confirmation came on Saturday. My older son(5) was "coaching" the younger one(2). "Do not boot to Windows, there are no games there!"
And how did I do it?
- Do not install games for kids to Windows
- Do not install MS Office on Windows
- Set Linux as the default operating system

Published on 2008-3-4 22:13:00 by Roman Mackovcak
Last week I was working on the performance tuning of a rails application. I ran a profiler and found something very interesting.
I found that there is a procedure that is called very often and takes a lot of time.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
14.99 18.13 18.13 43430 0.42 0.85 Mysql#get_length
8.84 28.82 10.69 172751 0.06 0.09 Kernel.===
8.40 38.98 10.16 306964 0.03 0.04 Fixnum#==
7.59 48.16 9.18 5566 1.65 30.60 Integer#times
6.42 55.92 7.76 7582 1.02 1.63 Mysql::Net#read
...
0.00 120.92 0.00 1 0.00 120920.00 #toplevel # File src/rails-1.2.3/activerecord/lib/active_record/vendor/mysql.rb
def get_length(data, longlong=nil)
return if data.length == 0
c = data.slice!(0)
case c
when 251
return nil
when 252
a = data.slice!(0,2)
return a[0]+a[1]*256
when 253
a = data.slice!(0,3)
return a[0]+a[1]*256+a[2]*256**2
when 254
a = data.slice!(0,8)
if longlong then
return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3+
a[4]*256**4+a[5]*256**5+a[6]*256**6+a[7]*256**7
else
return a[0]+a[1]*256+a[2]*256**2+a[3]*256**3
end
else
c
end
end class Mysql
def get_length(data, longlong=nil)
return if data.length == 0
c = data.slice!(0)
case c
when 251
return nil
when 252
a = data.slice!(0,2)
return a[0]+(a[1]<<8)
when 253
a = data.slice!(0,3)
return a[0]+(a[1]<<8)+(a[2]<<16)
when 254
a = data.slice!(0,8)
if longlong then
return a[0]+(a[1]<<8)+(a[2]<<16) +(a[3]<<24)+(a[4]<<32)+(a[5]<<40)+(a[6]<<48)+(a[7]<<56)
else
return a[0]+(a[1]<<8)+(a[2]<<16)+(a[3]<<24)
end
else
c
end
end
end I ran the profiler again and, well... a wisdom of my university times popped on my mind: “There is an elegant, simple, nice and obvious solution for each problem. Unfortunately, it is wrong!”
Performance remained the same. So, deeper investigation is needed! It was not difficult to find out that most of the times the “else” branch is executed. I tried something like this:
def get_length(data, longlong=nil)
return if data.length == 0
c = data.slice!(0)
return c if c<251
case c
when 251
return nil
when 252
a = data.slice!(0,2)
return a[0]+(a[1]<<8)
when 253
a = data.slice!(0,3)
return a[0]+(a[1]<<8)+(a[2]<<16)
when 254
a = data.slice!(0,8)
if longlong then
return a[0]+(a[1]<<8)+(a[2]<<16) +(a[3]<<24)+(a[4]<<32)+(a[5]<<40)+(a[6]<<48)+(a[7]<<56)
else
return a[0]+(a[1]<<8)+(a[2]<<16)+(a[3]<<24)
end
else
c
end
end % cumulative self self total
time seconds seconds calls ms/call ms/call name
11.26 11.25 11.25 43430 0.26 0.38 Mysql#get_length
8.73 19.97 8.72 5566 1.57 23.25 Integer#times
7.77 27.73 7.76 7582 1.02 1.63 Mysql::Net#read
7.27 34.99 7.26 5140 1.41 3.69 Array#each
5.52 40.50 5.51 139526 0.04 0.05 Fixnum#==
...
0.00 99.88 0.00 1 0.00 99880.00 #toplevel - Create a file called e.g. mysql_fix.rb
- Add there
require 'active_record/vendor/mysql'
class Mysql
def get_length(data, longlong=nil)
return if data.length == 0
c = data.slice!(0)
return c if c < 251
case c
when 251
return nil
when 252
a = data.slice!(0,2)
return a[0]+(a[1]<<8)
when 253
a = data.slice!(0,3)
return a[0]+(a[1]<<8)+(a[2]<<16)
when 254
a = data.slice!(0,8)
if longlong then
return a[0]+(a[1]<<8)+(a[2]<<16) +(a[3]<<24)+(a[4]<<32)+(a[5]<<40)+(a[6]<<48)+(a[7]<<56)
else
return a[0]+(a[1]<<8)+(a[2]<<16)+(a[3]<<24)
end
else
c
end
end
end - Put it into e.g. lib/zmok directory
- Add into your environment.rb following line
require File.join(File.dirname(__FILE__), '../lib/zmok/mysql_fix') 
Published on 2008-2-21 2:58:00 by Roman Mackovcak
Recently I was experimenting with ruby bayes classification. At first sight it looks like a difficult topic, but with the right libraries it is interesting and funny.
Before you start experimenting, you have to install 3 gems.
gem install classifier
gem install madeleine For the beginning, lets experiment with the plain bayes classifier.
require 'classifier'
bayes = Classifier::Bayes.new 'funny', 'sad', 'neutral'
# Train it slightly...
bayes.train 'funny', 'Finally all of them were smiling'
bayes.train :sad, 'Little ill puppy'
bayes.train :neutral, 'Tax declaration' The classifier is "trained", so lets ask it something interesting...
bayes.classify 'Everybody have to pay taxes'
=> "Neutral" # Remove the incorrect statement
bayes.untrain :neutral, 'Tax declaration'
# Train it right
bayes.train :sad, 'Tax declaration'
# And provide something neutral (if there is no statement for a category, the classifier does not work as expected.
bayes.train :neutral, 'Rainbow is full of colors' So, how does the classifier sees it now?
bayes.classify 'Everybody have to pay taxes'
=>'Sad' bayes.classifications 'Everybody have to pay taxes'
=> {"Sad"=>-9.43348392329039, "Neutral"=>-10.2035921449865, "Funny"=>-10.2035921449865}
The classifier that was created and trained is nice, but disappears as soon as you stop your ruby console. To make it more persistent, you have to use Madeleine class.
"Madeleine is a Ruby implementation of Object Prevalence, that is, transparent persistence of business objects using command logging and complete system snapshots."
require 'madeleine'
# Store the data into bayes-dir directory
madeleine = SnapshotMadeleine.new("bayes-dir") { bayes }
madeleine.take_snapshot
Next time load the classifier with command
madeleine = SnapshotMadeleine.new("bayes-dir")
# Perform more training
madeleine.system.train "sad", "Many people were injured by the earthquake"
# And test it once more
madeleine.system.classify 'smiling face'
=>'funny'
madeleine.system.classify 'strong earthquake'
=>'sad' The classifier is a nice piece of code. I did enjoy it, and hope you will enjoy it too.

Published on 2008-2-7 22:31:00 by Roman Mackovcak
I came to a situation where I needed to search my Active record, but I did not know which field contains the information. The solution with Ferret was just three steps away...
Let's say, you want to search Stories for 'Giant' keyword. You have to create a Ferret index in memory (ferret gem needs to be installed), index all active records and gather all IDs matching the keyword.
index=Ferret::I.new
Story.find(:all).each { |s| index << {:id=>s.id, :content=>s.inspect} }
index.search_each('Giant', :limit=>100) do |id, score|
puts "Active record ID: #{index[id][:id]} with score #{score}"
end 
Published on 2008-1-29 17:00:00 by Miroslav Škultéty
We needed to cache a Ruby class method calling the Ferret indexing engine. Yurii Rashkovskii developed a great library called Caches.rb.
When I googled it out, it seemed very simple to use and promised to do EXACTLY what I need (even the default timeout was JUST IT). I especially liked the very Rails-like tutorial Don’t tell, show me!. However, it required quite some effort to make it work, mainly because of the rather sparse documentation. Still, in the end the usage is very elegant, the solution is simple and it does what it promises. Thank you, Yurii!
To help our esteemed readers get faster over that less agreeable middle phase, here are a few tips:
- Downloading it: I tried gems but the gem list server seemed to be overloaded, and when it worked at last, I just got an older version (0.2.0). When checking out (or exporting) version 0.4.0 from SVN trunk directly, the trick was in finding out the latest working SVN URL:
ruby script/plugin install http://svn.verbdev.com/rb/caches.rb/trunk
- With all the typical Rails mixin stuff petrified in my mind, it took me a while to notice that caching should be declared AFTER the definition of the method to be cached, and not at the beginning of the class definition. The example in the documentation shows it, but it’s easily overseen.
- We do use Rails, so I included
class_cache_storage Caches::Storage::Globalas suggested here - For some reason (I suspect my shallow knowledge of Ruby ;-), I did not manage to successfully require ‘caches.rb’ from the plugin installation dir #{RAILS_ROOT}/vendor/plugins/caches.rb/lib, so I copied it to #{RAILS_ROOT}/lib, which helped.
- For similar reasons, I had to use a workaround to extend the class definition with caching, instead of the recommended way of extending conf/environment.rb by
ActiveRecord::Base.extend Caches::ClassMethodsSo our class looks as follows:
require 'ferret'
include Ferret
require 'caches.rb'
class FIndex
extend Caches
...
def self.search(user=nil, results_per_page=10)
...
end
class_cache_storage Caches::Storage::Global
class_caches :search
endN.B.: The class to be cached works with Ferret and not the DB, so it did not inherit from ActiveRecord.
- For a pure RoR developer, the terminology may be a little confusing (which indicates that Yurii can deal with more programming languages than just Ruby):
- class methods mentioned in the library description are obviously just a shorthand for “the methods of a class”
- in Yurii’s documentation, Ruby class methods are called static methods (as known in C/C++ or Java), and their caching is supported by class_caches (feature not available in caches.rb 0.2.0 from gems or RubyForge, but included in the more recent versions from SVN, like 0.4.0 we are using)

Published on 2007-11-13 22:41:00 by Roman Mackovcak
Sometimes it is necessary to reuse existing logic from stored procedures. This line of code shows how to call a stored procedure in Oracle.
ActiveRecord::Base.connection.execute('BEGIN do_the_calculation; END;') 
Published on 2007-10-24 5:27:00 by Roman Mackovcak
After a while my first enterprise prototype is finished and I have to summarize what was right and what was wrong during the period of prototyping.
Really nice surprise for me was the way of communication. The requirements were formulated more precisely then any requirement before, but not from the beginning. When I did start, the requirements were very vague, but after first screens and first few features the communication was excellent and clear. This was the phase of fundamental principles and relations creation.
After some time, the flow of requirements was stronger and stronger. It was necessary to start requirements management – yes, it is true. You cannot get rid of it.
In the middle of development users started to use it and a new set of “handy little” features was requested.
Later the system became very important and the users started to solve real production issues using the system.
Now, the system is almost finished. I mean – the necessary features are there, but sometimes it is not consistent. Especially the stuff that is used rarely. The enterprise is pushing me to pass it into production regime. And what are my lessons learned?
- The start will be painful. Be prepared to completely redesign the code and model.
- Scaffolding is for some time more than enough.
- It is not necessary to focus on good graphical desing from the beginning. Focusing on features is more important. In my case I did implement a nice design after 80-90% of features was implemented. And in fact, I did it because the environment was really ugly, not because customer did ask me to do it.
- Make sure you find the right group of people to prototype with. It is impossible to create a prototype without business experts.
- It is not important how much you boost your performance using good tools. You will always have more requirements than could be implemented. Requirements management is a must.
- Communicate clearly that you are working on a prototype. Otherwise you will be forced to make it a real application. Here I started to think about using grails for prototyping. Nevertheless, I have no experience to decide if it was a good idea or not.
- Be prepared for success! The application that will be created is in line with the requirements and heals the biggest pains of the business users. It is highly probable that the users will love it.
- Do not stick with one technology. Anything that makes the process faster is valuable. Eg. I did use Sybase PowerDesigner to generate “history keeping” triggers automatically. Adding a new table to my model was just few clicks and assigning the right trigger template.
- And last, but not least. Listen! Listen more! And make sure you understand that you are not the one who knows the business. You came there to help them to communicate their needs, not to show them how to do their business.

Published on 2007-10-3 3:43:00 by Roman Mackovcak
This article tries to explain how to convert existing class in Ruby on Rails to a class that can be used in polymorphic association class. As the beginning, I do recommend to read article about polymorphic associations. It explains what they are and how they work.
The whole process will be described on classes Picture (represents picture) and Item (an item that needs a picture).
1. First of all, it is necessary to create columns for the pictures table. The best way is to use migrations. So, create file e.g. 013_convert_pictures_to_polymorph.rb in your db/migrate directory. It should contain something like:
class ConvertPicturesToPolymorph < ActiveRecord::Migration
def self.up
# Change old item_id identifier to new picturable_id
rename_column :pictures, :item_id, :picturable_id
# Add type of association
add_column :pictures, :picturable_type, :string, :length => 50
# Fill in the type of association
execute "update pictures set picturable_type = \"Item\""
end
def self.down
# Bring it back
rename_column :pictures, :picturable_id, :item_id
remove_column :pictures, :picturable_type
end
end rake migrate 2. Once the appropriate columns were created, it is necessary to change the Item class. Change the
has_many :pictures has_many :pictures, :as => :picturable 3. Now change the Picture class. Change
belongs_to :item belongs_to :picturable, :polymorphic => true 4. Creating a new class enriched by pictures is simple. Just add
has_many :pictures, :as => :picturable 5. Last but not least, change your fixtures. The easiest way is to export the current data from your database. For this purpose I do use manage_fixtures plugin.
Good luck!







/bin/recykl