Monday, January 28, 2008

Ruby, Rails, Groovy, Grails, What's a programmer to do?

I'm doing some prototyping on a possible project for a client and have been getting my feet wet with the Grails Framework. I feel like know my way around Rails fairly well as I've done a few different small web applications in the framework and although there was a learning curve and Rails does have it warts, overall Rails really has saved me a TON of time and made me write better and well tested code.
For this project with my client, I'll be leaving it in their possession and feel that selling them on Groovy and Grails was a slightly easier sale as they already are a 100% Java shop. I think making the switch to writing Groovy, using their existing IDE (IntelliJ) and deployment in a J2EE container, would make them a little more comfortable than having to learn Rails. The JRuby guys are doing awesome work and if it was entirely up to me, I'd take the Rails route and consider using JRuby for production deployment if needed. But, getting them even to consider another framework was enough of a strain and if I told them I was leaving them an application in Ruby, I think I would most likely have been shown the door.

So, alas, I walk the Grails line. I must admit, it has been an interesting experience so far and one that I'd like to write more about in a future posting. I did however come across this blog posting in my research and have found it sums up very well some of the feelings I have for the whole Grails / Rails debate I see ensuing. I'd highly suggest reading the article.

Overall, I think each has it's place. I would agree that with Grails I find myself spending more time learning the framework because of poor or outdated documentation, and picking p Groovy the language relatively quickly. Where with Rails, I find myself learning the framework quickly, but taking more time to learn Ruby. It might however have to do with the fact that I learned Rails first and in some ways have to break my mind of some of the differences between what I learned in Rails and how it's done in Grails.

Regardless of which side you land on, I think it's worth your time to atleast investigate and learn about these frameworks as these are going to become more and more popular methods in developing applications as time marches on.

Tuesday, January 1, 2008

Upgrade to Rails 2.0

Well, to usher in the New Year, I bit the bullet today and tried upgrading one of the applications I built for my client to Rails 2.0 . The process to do the upgrade was relatively painless. The whole idea of Rubygems is awesome and is something I feel that the Java community is horribly lacking.
Installing Rails 2.0.2 was a simple as:

>sudo gem install rails

And then changing the line in the environment.rb to:

RAILS_GEM_VERSION = '2.0.2' unless defined? RAILS_GEM_VERSION

The issues though came in when I actually tried to run the application. Here's a brief rundown of the refactoring that I had to do and some gotchas that maybe other will run into.

1. Pagination - I had heard all of the warnings that the default pagination was going to be taken out of Rails 2.0, but like more programmers I am somewhat lazy ( or too busy ) to implement changes until I really NEED to. Well, if you upgrade to Rails 2.0 and you use the default pagination functions in Rails 1.2, you will NEED to do something else. It has been ripped out for Rails 2.0. I must say I agree with the the idea to pull it out as pagination is something that really should be done by a plug-in. After some searching I found a two options for people in my same situation.

a. classic_pagination - This is the plugin that will give you the same functionality of the old Rails 1.2 pagination. Many in the Rails community frown on the use of the old code for performance reasons, flexibility and good object oriented design.

b. will_paginate - This is the plugin that is seems like the Rails community is backing going forward for pagination. It offers some advantages of the old pagination methods and doesn't require too much refactoring to implement. Here is a good screencast on using it.
I decided to go with will_paginate since this is more the standard and new projects going forward this is what I will probably use, so it made sense for me to get aquainted with how it works. It turned out to be actually very easy to make the changes. He is an example of a change in the controller that I needed to make for "Jobs".

This:
@job_pages, @jobs = paginate(:jobs, :order => 'deadline')

Was changed to:
@jobs = Job.paginate(:page => params[:page], :order => 'deadline')

and in my view this code:
Page Number: <%= pagination_links(@job_pages, :params => {'job[filter]', @job_filter }) %>

was changed to simply:
<%= will_paginate @jobs %>

Much easier to read, understand and maintain. I'd suggest watching the screencast I mentioned above to learn more.

2. Nested RESTful routes - This was very annoying and was a little difficult for me to find much information on how to fix it. It seems like when you define a nested route in the routes.rb in Rails 2.0, the helper methods that are created don't behave the same or work the same as they did under Rails 1.2 This is what I had previously.

We have a relationship with jobs containing artifacts. So in our routes.rb:

map.resources :jobs do |job|
job.resources :artifacts
end

and in the a show.rhtml view had:

artifacts_path(@job)

When running under Rails 1.2 this works fine and generates the url

/jobs/1/artifacts URL.

Under Rails 2.0 we get an error:

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.to_sym

Annoying. Well it turns out you have 2 options.
a. Modify your routes.rb to be

map.resources :jobs do |job|
job.resources :artifacts, :name_prefix => nil
end

b. Change the call to artifacts_path to instead be:

jobs_artifacts_path(@job)

There is information on this helper methods here. Thank god I found this reference. That is one thing that I do find frustrating about Rails is the lack of the documentation I was able to find when going through an upgrade. It seems like this issue I ren into should have beein BIG BOLD letters warning people that old RESTful methods don't work the same with out the changes that I mention. Anyway, I digress. I decided to go with the more simpler change of adding :name_prefix => nil to my routes.rb since I was worried about making sure I found all of the helpers. Hopefully this is the right choice and will work in all my cases. It seems to work for the time being.

3. Running unit tests in Textmate - It seems like there is some issues with a file called Builder.rb and it conflicting with Builder.rb in Rails 2.0. I couldn't run my tests in Textmate until I did what was described here. Not a big deal, but again... annoying and nothing that I have seen other documentation. With 75% of the Rails community using TextMate I'm surprised that at the very least DHH didn't mention it in the release notes for Rails 2.0

4. Capistrano - Capistrano 2 is what is now used by default with Rails 2.0. I tried running a simple 'cap deploy' after upgrading an have been getting some odd errors. I need to track down exactly what is going on. I had thought that deploy.rb was backward compatible, but I guess not. For now I have been doing `cap _1.4.1._ deploy` and forcing it to use the old version for now. I'll track this down shortly.

5. Flash.now - So, I re-ran by functional tests and started getting failures. I have the following line in my application.rb

flash.now[:error] = "You are not authorized."

When running under 1.2.3 and my functional test I have an assert to validate that the error returns in the flash.

assert_equal "You are not authorized", flash[:error]

However, when running under Rails 2.0.2, THE FLASH IS NOT RETURNED! Why is that?

If I change the line in the application.rb and remove the .now to be

flash[:error] = "You are not authorized."

THE TEST PASSES! Not sure why this is in the case. I haven't seen anything in the release notes that mention an upgrade would cause this. Maybe I'll send a post to the RUM group to see if others have seen something similar.

All in all though, the upgrade to 2.0.2 hasn't been too bad. I guess I was hoping that it would be trivial, but I guess what can I expect? I did come from 1.2.3 all the way to 2.0.2 and I can't expect everything to just automatically work right out of the box. I has however only been 8 months since I started work on this system and am surprised the versions that we are up to in Rails. I'm excited to see where things are in at in another 8 months!