CATEGORY: Ruby On Rails

You can use Module as a helper to store common methods to be shared across different classes.

By including the module in your class, you inherit its methods. But, problem pops up, when on some cases you need to call the helper method from a class mehod instead of an instance method. And you know you can’t call an instance method directly from a class method.

So this was what I did.

module Helper
    self.included(base)
        base.extend(self)
    end

    def hello
        "Hello world"
    end
end

class Service
    include Helper

    def instance_call
       hello
    end

    def self.class_call
       hello
    end
end

Service.new.instance_call # returns 'hello world'
Service.class_call        # returns 'hello world'

Exploit TechPluit has just embarked on a new Ruby On Rails project with Exploit Technologies Pte. Ltd., a commercial arm of
Agency for Science, Technology and Research (A*STAR) that helps to identify, protect and exploit Intellectual Property (IP) created by the Research Institutes (RIs) funded and managed by A*STAR.

This project marks the beginning of Pluit’s involvement in commercial project using Ruby On Rails (RoR), and Pluit’s second RoR project after BookJetty (the next release, coming up real soon). Although I am happy for this achievement, but behind it, it was a tough job to push RoR to the corporate world who likes the word ‘Enterprise’.

You can say RoR is still relatively new, as version 1.0 was released in December 2005; but in a hot open-source world — a year is relatively very long. Lots of stuff can happen within a year, just look at how much RoR has changed since v1.0.

In fact, RoR has spread like a wild-fire in US, Japan, Europe and Canada. But in Singapore, people and companies are still very careful about RoR. So questions like this are common, as I was also asked:

“Who is backing Rails and Ruby?”

“Are they going to be another abandoned open-source project in the next few years?”

Well, you can’t blame them, there’s a common saying here that says, You don’t love, because you don’t know. But does BIG always mean good? How about looking at EJB 1.0 and 2.0, JSTL, and Java Server Faces, are they good? I am not sure about you, but people do question, even though it is backed by big company. And I meant really BIG company.

With this project going, I hope in the next couple of months, there will be greater acceptance for RoR. And speaking from devleoper’s perspective, it is NOT the end result that counts, but how do you achieve the result that really counts. With RoR, all I can say is HALLELUJA.

It all started with Nick asking a question like this in Singapore Ruby Brigade. How come?

String === String
=> false
# but
String == String
=> true

Let’s start with the easy one first:

Equality (==, eql?, equal?)

#== is the common equality method that compares object values, ignoring the object id. #eql? is the alias of #==, so they are the same. Btw the “#” prefix means it is an instance method (just in case), without the prefix, it means a class method.

The stricter version of is #equal? compares the object id. Example:

"test" == "test"         
# returns true, both have the same value, i.e. "test"

"test".equal?("test")  
# returns false, because "test" (left) is a different object from "test" (right), where "test".__id__ != "test".__id__

Case Equality (===)

=== is the case equality method, in English it means it is called internally when you use ‘case’ statement, but of course, it can also be called outside the case statement.

=== method functions differently, depending on the caller class type.

If you call it on a Class, it will check if the compared object is an instance/descendant of the class. On Object, it is the same with #== method. Please refer to Ruby documentation for more information on how it performs on different class types.

String === "test"    
# returns true because "test" is an instance of String

"test" === "test"
# returns true, because both objects have the same value or "==" returns true

"test" === "different test"
# returns false, because the two objects have different values.

Just a bit more spice, on Ruby on Rails (RoR) framework, the Range class overrides “===” method to returns true if the compared value is found in the in the range values.

1..10 === 1    # returns true
1..10 === 11   # returns false

case var
   when 1..10
       "do some stuff here"
   when 11..20
       "do something else here"
   else
       "out of range"
end

So back to the one-million-dollar question, why then String === String returns false?

Calling String in the runtime environment, returns a Class object that represents String class type. If you call String.__id__, it will return the object id of Class object. Thus:

String === String
# returns false, because String (right) is treated as a Class object, passed as an argument to String  "===" method.

And… I think you get it, obviously Class object is not an instance of String class. Sweet.

And why String == String returns true?

You should be able to answer it by now. =)

Overriding Methods in Ruby

THU, 5 OCT 2006

If you are new to Ruby, you may bump into some confusion when overriding methods, especially when you still need to refer to the old or parent methods. Just to share some notes I have taken on overriding methods in Ruby.

You can override a method by either extending a class or by re-declaring an exisiting class with just the new methods.

Let’s dive into codes, Ruby codes speak a thousand words.

Overriding Parent Instance Method

This is the typical way in Object-Oriented programming, by extending a class.

class Parent
    def call_method
        'parent'
    end
end

class Child < Parent
    def call_method
        super + '-child'     #return: 'parent-child'
    end 
end

Overriding Parent Class Method

Class methods are a bit more confusing, because there are different ways to declare them. Well, welcome to ruby, there are a lot of magic here.

There are three ways to declare class methods:

class ClassName
    def ClassName.method_1
        ...
    end

    def self.method_2
        ...
    end

    class << self
        def method_3
            ...
        end

       def method_4
           ...
       end
    end
end

To override a class method:

class Parent
    def self.call_method
        'parent'
    end
end

class Child < Parent
     def self.call_method
         superclass.call_method + '-child'    #return: 'parent-child'
     end

end

Overriding Method of Existing Class

To override a method in an existing class, you just have to re-declare the class with the new methods. If you need to call the old method in your new method, you first have to create an alias of for the old method. You can use either alias or alias_method. This is something that I dont’ see in Java, pretty cool.

Note that you don’t need to redeclare Parent extension. And also note the difference in declaration between alias and alias_method; alias is a reserved keyword in Ruby, while alias_method is just a function call.

class Child
  alias old_call_method call_method

  def call_method
     old_call_method + '-new'   #return 'parent-child-new'
  end
end

class Child
  alias_method :old_call_method, :call_method

  def call_method
     old_call_method + '-new'   #return 'parent-child-new'
  end
end

Or you can also do it this way:

class Child
   alias_method :old_call_method, :call_method
   alias_method :call_method, :new_call_method

   def new_call_method
     old_call_method + '-new'   #return 'parent-child-new'
   end
end

# If you are using RailsOnEdge, this is the shortcut 
class Child
   alias_method_chain :call_method, :extra
  
   def call_method_with_extra
        call_method_without_extra + '-new'    #return 'parent-child-new'
   end
end

BookJetty on Ruby On Rails

MON, 25 SEP 2006

After downloaded the latest version of Hibernate, Spring and Acegi Security, configuring the long list of XML configurations, just about to start working on the next enhancement for BookJetty; I decided to make a U-turn to re-code BookJetty from scratch again using Ruby On Rails (RoR).

I know it is crazy, and it sounds like a lot more work at first thought, but my developer instinct assured me, with RoR, I’ll be able to save a lot more time in the future. Besides, I’ll be able to learn more about RoR, so what the heck.

Strange, somehow, I get more excited.

If your tables have created_at/created_on and updated_at/updated_on columns, Ruby On Rails (RoR) framework is smart enough to auto-assign the date/time value, without you writing a single line of code.

That’s great. But when you need to keep track of created_by and updated_by, you have to manually update your controllers to set the values. This obviously contradicts with Don’t Repeat Yourself (DRY) principle of Ruby. So, as a good and obedient Ruby programmer, let’s work around that.

For a start, RoR wiki is the best place to find information, it provides a write up on how to enhance ActiveRecord::Base to auto update created_by and updated_by. The tricky part is how do you retrieve the currently logged-in user, which is usually only exposed in controller and view layers, but not the data access layer.

If you have read the article, it shows a clever way by adding a class method (current_user) to user.rb, and updating aplication.rb to set currently logged-in user:

user.rb

cattr_accessor :current_user

application.rb

before_filter do |c|
    User.current_user = User.find(c.session[:user]) unless c.session[:user].nil?
end

This way however is prone to concurrency issue, because RoR Dispatcher is not thread-safe and class variable is a single instance variable. Thus concurrent thread executions may provides current_user value with the other concurrently-executing-logged-in user.

Another way is to use Thread.current. With it, you can store a short-live variable value for the executing thread, and it is thread-save.

Now, you only need to update the application.rb and leave user.rb intact. Copy usermonitor.rb in to the /lib directory and you are done, a RoR framework that auto-updates created_by and updated_by, isn’t RoR wonderful?

application.rb

class ApplicationController < ActionController::Base
  ....

  before_filter :set_current_user
  
  def set_current_user
    Thread.current['user'] = session[:user]
  end
end

usermonitor.rb

module ActiveRecord
  
  module UserMonitor
    def self.included(base)
      base.class_eval do
        alias_method_chain :create, :user
        alias_method_chain :update, :user

        def current_user
          Thread.current['user']
        end
      end
    end

    def create_with_user
      user = current_user
      if !user.nil?
        self[:created_by] = user.id if respond_to?(:created_by) && created_by.nil?
        self[:updated_by] = user.id if respond_to?(:updated_by)
      end
      create_without_user
    end
    
    def update_with_user
      user = current_user
      self[:updated_by] = user.id if respond_to?(:updated_by) && !user.nil?
      update_without_user
    end
    
    def created_by
      begin
        current_user.class.find(self[:created_by]) if current_user
      rescue ActiveRecord::RecordNotFound
        nil
      end
    end
   
    def updated_by
      begin
        current_user.class.find(self[:updated_by]) if current_user
      rescue ActiveRecord::RecordNotFound
        nil
      end
    end
  end
end

Please note the following changes to usermonitor.rb as compared with the version found in the wiki:

  • Use alias_method_chain for cleaner code, it overrides ActiveRecord::Base#create to call create_with_user, and link the previous ActiveRecord::Base#create method with create_without_user.
    alias_method_chaing is currently only available for for RoR on Edge
  • Overriding ActiveRecord::Base is no longer necessary due to auto-retrieval of model name through current_user.class, which assumed to return the user object instead of just the user id.

Finally, remember to add the following codes to extend ActiveRecord::Base with UserMonitor:
config/environment.rb

require 'usermonitor'
ActiveRecord::Base.class_eval do
    include ActiveRecord::UserMonitor
end

UPDATE: After delving with RoR for a while, I found out that Rails is based on CGI request model, thus there is not thread safety issue, and you don’t necessarily need to use Thread.current to store your current user, and an instance variable is as good.

When doing functional test, sooner or later you will need to do some testing with cookie, for example when you need to test the infamous ‘Remember me’ functionality.

It is easy to do that in Rails with some points to take note:

To set a cookie in a request:

@request.cookies['name'] = CGI::Cookie.new('name', 'cookie value')

To retrieve a cookie after a response:

cookies['name']
Note: Use a string for cookie name, symbol somehow returns nil in functional test.

And a sample of Remember Me functional test:

def test_login_with_remember_me
    post :login, :username => 'herry', :password => 'passwd',
        :rememberme => '1'
    assert session[:user]
    assert cookies['auth_token']
    assert_response :redirect
    assert_tag :tag => 'div', 
        :child => /[replace with your error message]/

    # reset user session and set request cookie
    session[:user] = nil
    @request.cookies['auth_token'] = cookies['auth_token']    
  
    get :protected_page
    assert_response :success
    assert session[:user]
end

It has been a while since I last posted a blog on rails. I have been tied up with lots of stuff lately. And I just got my time back to move on with my first Rails project to build QuoteJetty. The ride has been fun, though many times I still have to google to find answers for issues that are not covered in Rails books.

One thing that I bumped into is the usage of flash[:notice].

I found out that flash[:notice] is meant only for redirect action, because the message is only cleared after at the end of redirected view request. So if you don’t redirect the request, and you click on the next request, that message will still be displayed.

But sometimes, we just want to display custom error messages only for current request without the redirection (esp. for non-ActiveRecord error messages). So the option is to use flash.now[:notice]. It clears the flash message at the end of current request (without redirection), e.g.

def some_method
    .....
    flash.now[:notice] = 'some message'
end

But there is an issue with functional testing using flash.now[:notice]. Since the message is cleared at the end of the request, you won’t be able to retrieve the flash[:notice] value in your functional test. But no worries, here is the alternative check, use assert_tag.

assert_tag compares the actual html output of your test in a convenient way, just like most of Ruby methods. Click here for the API doc.

def test_method
    ....
    ....
    assert_tag :tag => 'div', 
        :child => /[replace with your message]/
end

Windows command console is quite primitive, it is good to have the power of Unix console on your Windows. If you are like me, you could have installed Cygwin and you probably have installed Ruby using One-Click Ruby Installer, but encountered some problems running ruby, rails and other ruby-related commands on Cygwin.

Well, same here, and I think it is easier to install a seperate copy of Ruby under Cygwin. Fixing the path differences between Windows and Cygwin consoles can be messy, here are some tips to install RoR on Cygwin:

  1. Install a seperate copy of Ruby using Cygwin setup wizard. Expand All > Devel and select ruby and proceed with the setup.

  2. After you have installed Ruby, download Ruby Gems, extract the setup files to a temporary directory, and when you try to run the setup, you probably will encounter an error.

    ruby setup.rb
    ruby: No such file to load -- ubygems (LoadError)

    Tips:

    When you install Ruby using One-Click installer, it will set an environment variable RUBYOPT=rubygems. It tells ruby to load rubygems library when running a ruby file. You have not installed Rugy Gems, thus the setup.rb execution failed.

    Just unset RUBYOPT variable and re-run the Ruby Gems setup:

    unset RUBYOPT
    ruby setup.rb

  3. Then you can install Rails using Ruby Gems by running:

    gem install rails --include-dependencies

  4. You have irb configuration file (.irbrc file) under your windows home directory, and you still want to use it in Cygwin, create a symbolic link to the file in Cygwin home directory

    cd $HOME
    ln -s [/path/to/windows-user/homepath/].irbrc .irbrc

I’m a New Ruby Convert

MON, 27 MAR 2006

Human being always craves for something better, if you are staying in rented room, you wish for a flat, when you have the flat, you wish for a condo.

It’s the same with software development, we, the developers, mere mortals that have becomed slaves of computers, always wish for a better programming language. A more efficient and easier to maintain codes. Object oriented (OO) programming language especially Java and C# have been gaining lots of adoption for the past few years because it is easier to maintain your codes in object oriented ways.

Though OO programming language is good, it still lacks the agility of scripting language. With customers demand more for each dollar spent, I too, was pushed to yearn for something better. And today I find Ruby; it somehow manages to combine the goods of OO and agility of scripting language. And in today’s context, it simply makes sense, and I’ve decided to be a new Ruby convert.

The DRY (Don’t Repeat Yourself) principle is just too right to be true. It’s amazing to see how few lines your codes can be. The other principle “Convention Over Configuration” saves much of your trouble if you are to try to figure them out yourself. And the best part is all Rubyists speak the same conventions.

Though Ruby is still young, it has been gaining lots of momentum and it will absolutely be the NEXT BIG THING.