Friday, 20 February 2009

Moving to Rails 2.2.2

Having just made the move from 2.1.2 to 2.2.2, I hought I wold share some of the issues I came across. There was a bug in 2.1.2 which meant that the image_tag method appended a dot to the end of the image filename, which has been resolved, so that is a good start.

Partials
The way you use partials has been updated in Rails 2.2. While the changes are certainly an improvement, modifying code is not fun (I had about 50 changes to make; thank goodness functional testing will catch your mistakes).

The basic change is that render_partial and render_partial_collection now accept a single hash, rather than a string indicating the file and the important variable, and can be accessed through the render method (thanks to mcclelland for pointing that out). The hash should have the file mapped to the :partial key, and any variables you want in your partial go in a hash mapped to the :locals key (so immediately we can see this is an improvement; you can pass as many of these as you want). These are accessed like local variables in your partial (but really as method calls, I assume). Class variables can be accessed in your partial just as they can in normal views.

To render a collection, just map it to :collection. You can also map any HTML code you want between the elements of your collection to the :spacer key. Rails works out that if :partial is present, it has to render a partial, and if :collection is present, it has to render that partial as a collection, so I would use render for everything (and personally, I would have removed or made private render_partial and render_partial_collection given that we all have to change our code anyway).

Let us see how it has changed. In this first example, a single variable is passed, which I have called :list (so I do not have to change the partial itself):
# Old version
<%= render_partial 'list', @events %>

# New version
<%= render :partial => 'list', :locals => { :list => @events } %>

Here is a table that uses two partials. The first, for the headings, requires no variables. The second is passed an array mapped to :collection:
# Old version
<table width="100%">
<%= render_partial 'table_headings', nil %>
<%= render_partial_collection 'table_row', @samples %>
</table>

# New version
<table width="100%">
<%= render :partial => 'table_headings' %>
<%= render :partial => 'table_row', :collection => @samples %>
</table>


Error pages
There are three error pages in the public directory, which Rails uses when something goes wrong in the production environment (rather than giving error details). I think these were passed through ERb previously. This is no longer the case.

Testing
When running tests, if the system encounters an error, it just gives up, instead of noting the error, and moving on to the next test. I strongly suspect this is a bug.

If a user tries to do something when logged in, but without the required role, he gets redirected to the root page. In the controller, I specify a controller and an action. Previously, I could specify that in the redirect too, but not now. It took some seaching to find that I needed this:
assert_redirected_to "http://test.host/"


Another change in that Rails now generates tests in a different form:
#Old format
def test_my_method
some_code
end

#New format
test "my method" do
some_code
end

The old format still works - no need to change all your old tests. Rather than creating a whole new set of methods, you are now invoking the test method... which then defines a new method by prepending test_ to the name, and then doing exactly the same as it did previously.

Tomcat problem
Having got everything working fine in the development environment, and all tests passing, I was confident to move to the production environmemt...
19-Feb-2009 14:40:58 org.apache.catalina.core.ApplicationContext log
SEVERE: unable to create shared application instance
org.jruby.rack.RackInitializationException: undefined method `cache_template_loading=' for ActionView::Base:Class
...
19-Feb-2009 11:23:00 org.apache.catalina.core.ApplicationContext log
SEVERE: Exception caught
java.lang.NullPointerException
at org.jruby.rack.DefaultRackDispatcher.process(DefaultRackDispatcher.java:32)
at org.jruby.rack.RackFilter.doFilter(RackFilter.java:51)

Oh dear. After much searching (and updating JRuby from 1.1.4 to 1.1.6), I found this forum thread. The solution was to remove the following line from config/environment/production.rb (may also be in config/environment.rb):
config.action_view.cache_template_loading = true


A has_one problem
An obscure bug I came across for the has_one/belongs_to relationship. When I attempted to access one model from the other, I got a NoMethodError exception, and a complaint that I was tryong to do nil.include?. My has_many/belongs_to relationships worked fine. The problem was related to setting the time zone. I have no idea how that can be, but I was not the only one:
http://www.nabble.com/Strange-error...-td21313953.html
http://www.railsformers.com/article/activerecord-timezone-settings-bug

Anyway, the solution is to delete or comment out the old time zone configuration in config/environment.rb, and put in a new one.
  #config.time_zone = 'UTC'
config.active_record.default_timezone = :utc


Additional: Rails 2.3.2 has been out for a while, and I have tried using that. The only noticeable difference was application.rb was renamed to application_controller.rb. Right up until I tried to deploy on Tomcat and it all stopped working. There is a word around here, but I have a suspicion this assumes you have created your project with a more recent version of Rails than I did. Anyway, it did not work for me, so I am back on 2.2.2.

Further addition: Going back to 2.2.2 caused my unit tests to fail mysteriously, with rake just giving up (though functionals and integration tests were fine, and each unit test on its own was fine). It turned out that new models I had added with 2.3.2 had an additional test in test/units/helpers, and this was upsetting the rake task (possibly because I had deleted the associated helper files).

Struggling with Ruby: Contents Page

Friday, 13 February 2009

The Ruby Proc

In Ruby a Proc (short for procedure) is a block of code, bound to a variable (closely related to a block, discussed here). As is always the way in Ruby, a Proc is an object, and so can be created with the new method, though, as discussed later, it is generally preferable to use the lambda method. Here are some examples (expanding on those in the Ruby documention):
# A Proc can have one, none or many arguments
times7 = Proc.new {|n| n * 7 }
statement = Proc.new { 'from statement' }
multiply3 = Proc.new {|x, y| x * y }

The code in the Proc object can be invoked by using the call method.
p times3.call(12)               #=> 36
p times5.call(5) #=> 25
p times7.call(8) #=> 56
p times3.call(times5.call(4)) #=> 60

p statement.call #=> "from statement"
p multiply.call(4, 3) #=> 12

You can pass around Proc objects like any other object:
def gen_times(factor)
return Proc.new {|n| n*factor }
end

class ProcTest
# Class variable is a Proc
@@times13 = Proc.new {|n| n * 13 }

# Method uses various Proc objects
def test
times11 = Proc.new {|n| n * 11 }
p times11.call(3)
p @@times13.call(7)
times2 = gen_times(2)
p times2.call(19)
end

# Method uses a Proc passed as an argument
def test_argument prc
p prc.call(4)
end
end

# ProcTest object instantiated, and methods called
pt = ProcTest.new
pt.test
pt.test_argument Proc.new {|x| x + 5}

Instead of using call, you can invoke the code using square brackets notation. The following are equivalent:
multiply.call(4, 3)
multiply[4, 3]


Proc.new vs lambda
If you call a Proc with too few arguments, Ruby will pad them out with the nil object, so multiply.call(14) above would invoke the Proc code with 14 and nil (which would generate an error in this case). Any extra arguments are simply discarded.

The Kernal has a method lambda (there is also a method proc, which reportedly does the same as Proc.new, but I found it identical to lambda) which will also give a Proc object, but in this case the Proc will raise an ArgumentError is the argument count is wrong.
count_nils_new = Proc.new {|x, y, z|
"#{x.nil?} #{y.nil?} #{z.nil?}"
}

count_nils_lambda = lambda {|x, y, z|
"#{x.nil?} #{y.nil?} #{z.nil?}"
}

# The 4 is quietly discarded
p count_nils_new.call(1, 2, 3, 4)

# The method is sent 1, 2, nil
p count_nils_new.call(1, 2)

# The method is sent nil, nil, nil
p count_nils_new.call

# This is fine
p count_nils_lambda.call(1, 2, 3)

# These will all generate an ArgumentError
p count_nils_lambda.call(1, 2, 3, 4)
p count_nils_lambda.call(1, 2)
p count_nils_lambda.call

Proc objects have an arity method that can be used to determine how many arguments the Proc is expecting.

Using return in a Proc
Using an explicit return in a Proc object created with Proc.new (but not lambda) will cause the calling method to return that value.
def with_return_and_new
prc = Proc.new { return 'This is printed' }
prc.call
'Never seen'
end

def no_return_with_new
prc = Proc.new { 'no_return_with_new' }
prc.call
'This is printed'
end

def with_return_and_lambda
prc = lambda { return 'with_return_and_lambda' }
prc.call
'This is printed'
end

p with_return_and_new
p no_return_with_new
p with_return_and_lambda

It seems that the Proc object is returning not just the value, but the return command too. In general, therefore, it is a bad idea to use an explicit return inside a Proc object defined with Proc.new (if only because the effect will be confusing to anyone with out a good understanding of Ruby peculiarities). This is discussed more here:
http://innig.net/software/ruby/closures-in-ruby.rb

API for the Proc object:
http://www.ruby-doc.org/core/classes/Proc.html

See also:
http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-and-methods/
http://blog.sidu.in/2007/11/ruby-blocks-gotchas.html

Struggling with Ruby: Contents Page

Sunday, 8 February 2009

The Singleton in Ruby

When I first read about singletons in Ruby, I assumed this was a reference to the singleton pattern; perhaps the classic example of a pattern, and in my opinion not much use (actually Ruby has a Singleton module for doing just this). However, in Ruby the singleton is something else entirely.

The singleton is a method that is attached to a single instance of a class. Here is a simple example:
s1 = 'what'
s2 = 'where'
s3 = 'when'

def s1.hello
p "Hello world"
end

class << s2
def hello
p "Hello world"
end
end


s1.hello
s2.hello
begin
s3.hello
rescue NoMethodError
p $!
end

p s1.singleton_methods
# => ["hello"]
p s2.singleton_methods
# => ["hello"]
p s3.singleton_methods
# => []

Three strings are created. The first two have singleton methods added to them in slightly different ways. The singleton methods can be invoked on that specific instance, but not on any other object of that class. Finally, the singleton_methods method is invoked to show how these methods can be listed.

Technically, the object itself does not get a new method. Objects can only hold variables, not methods. Rather, the object has a metaclass, or virtual class, and this metaclass is where the new method is. This is what class << s2 is accessing.

Class methods
You can also add singleton methods to the class, where they become class methods. The logic here is that the class is itself an object, and these methods are being added to a single instance of the Class class. This code illustrates three ways to add a singleton to a class.
def String.goodbye1
p "Goodbye world (1)"
end

class String
def self.goodbye2
p "Goodbye world (2)"
end
end

class String
class << self
def goodbye3
p "Goodbye world (3)"
end
end
end

p String.singleton_methods
# => ["goodbye3", "goodbye2", "goodbye1"]

It is interesting to note that "String" is actually a constant that holds a Class object, and this is why it is capitalised.

Note: Some believe that class << self is bad; this suggests there may be more going on here.

The singleton_methods method returns all methods for the class that are not inherited from a superclass. Use singleton_methods false to exclude methods from modules.

See also:
http://ola-bini.blogspot.com/2006/09/ruby-singleton-class.html

http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

Struggling with Ruby: Contents Page

Tuesday, 3 February 2009

Modules

A module is a collection of methods and constants, much like a method. However, a module cannot be instantiated. Instead, a module is added to an existing class or object to create a "mixin". Here is an example of a module, with both a method and a constant defined:
module TestModule
TEST_CONST = 1000

def hello
p "Hello"
end
end

The are two ways to add a module to your class, using the keywords include or extend:
class TestClass1
include TestModule
end

class TestClass2
extend TestModule
end

The include statement causes all the methods in the module to be added as instance methods, and also allows the constants to be accessed through the method. In contrast, the extend statement adds all the methods as class methods, and does nothing with the constants. Let us look at the constants first:
p TestModule::TEST_CONST
p TestClass1::TEST_CONST
begin
p TestClass2::TEST_CONST
rescue NameError
p $!
end

The class methods. TestClass2 had the module added using extend, so the method in the module is a class method:
begin
TestClass1.hello
rescue NoMethodError
p $!
end
TestClass2.hello

Finally the instance methods. TestClass1 had the module added using include, so the method in the module is an instance method. Note that you can add a module to an object at run time, but in that case the extend keyword is used:
# Create some instances
tc1 = TestClass1.new
tc2 = TestClass2.new
tc2too = TestClass2.new

# Methods accessible at the instance level
tc1.hello
begin
tc2.hello
rescue NoMethodError
p $!
end

# Module added at runtime
tc2.extend TestModule
tc2.hello
begin
tc2too.hello
rescue NoMethodError
p $!
end

I think the logic here is that extend is used for singletons; a single class or a single instance of the class.

Instantiation
Ruby will invoke the included or extended methods in your module, if they exist, when the module is included or extended respectively. These have to be defined as class methods - even though this is not a class. As far as I know, this is the only time you do tat for a module. Both methods should take a single parameter; the object or class to which the module is being added. An example:

module TestModule
def self.included base
p "I am being included by #{base}"
end

def self.extended base
p "I am being extended by #{base}"
end
end

class TestClass1
include TestModule
end

class TestClass2
extend TestModule
end

p 'Classes now defined'

tc2 = TestClass2.new
tc2.extend TestModule

# Output
#
# => "I am being included by TestClass1"
# => "I am being extended by TestClass2"
# => "Classes now defined"
# => "I am being extended by #<TestClass2:0x987a33>"

See also:
http://www.juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby/

Struggling with Ruby: Contents Page