Thursday, December 24, 2009

Implementing Payson API Integration 1.0 in Ruby

To do payment using Payson API integration 1.0 you need to follow 3 steps.
  1. Request to initiate a pay request (in return it will send you back a token)
  2. Redirect client to Payson site using that token
  3. After client completes the payment, Payson will redirect the client back to your site and you can check the payment status and update status of payment on your application
Payson api cycle

Plugin used

RestClient is nice API to handle http request and response.

Step 1 (Request to initiate a pay request)

To be able to use Payson API integration you must have,
AgentID: XXXX
MD5-key: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
For a pay initiate request you can see the specification here. Before you integrate the API in your application you can make a curl http call just to check if every thing works.
curl -H "PAYSON-SECURITY-USERID:XXXX" \
-H "PAYSON-SECURITY-PASSWORD:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" \
-d "receiverList.receiver(0).email=test@gmail.com&receiverList.receiver(0).amount=10&returnUrl=http://localhost:3000/payson_return/56&cancelUrl=http://localhost:3000/payson_cancel/56&memo=test&senderEmail=sender@gmail.com&senderFirstName=A.K.M.&senderLastName=Ashrafuzzaman" https://api.payson.se/1.0/Pay/ -o payson.out
Here PAYSON-SECURITY-USERID is AgentID and PAYSON-SECURITY-PASSWORD MD5-key. And as you can see PAYSON-SECURITY-USERID and PAYSON-SECURITY-PASSWORD (the authentication fields) will have to be send in the headers of the request. Now it should return a message which looks like,
responseEnvelope.ack=SUCCESS&responseEnvelope.timestamp=2009-11-15T17%3a14%3a03&responseEnvelope.version=1.0&TOKEN=4ecce14b-a4c7-4990-9814-db8aa2e97553
The response will contain a token which will be used to do the pay request.
Now let us see the ruby version of the curl request,
params_list = { 'receiverList.receiver(0).email' => reciever_email,
  'receiverList.receiver(0).amount' => recieving_amount,
  'receiverList.receiver(1).email' => more_receiver_email, #you can send money to more then one account
  'receiverList.receiver(1).amount' => more_receive_amount,
  'returnUrl' => callback_url,
  'cancelUrl' => cancel_url,
  'memo' => description,
  'senderEmail' => sender_email,
  'senderFirstName' => first_name,
  'senderLastName' => last_name }

header_list = {'PAYSON-SECURITY-USERID' => 'XXXX', 'PAYSON-SECURITY-PASSWORD' => 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'}

response = RestClient.post 'https://api.payson.se/1.0/Pay/', params_list, header_list

Step 2 (Redirect client to Payson site)

Now parse the response and redirect to Payson site for client to complete the payment.
response_hash = parse_response(response)

if response_hash['responseEnvelope.ack'] == 'SUCCESS'
  logger.info "Payson pay response #{response}"
  @signup.payson_token = response_hash['TOKEN']
  @signup.save!
  redirect_to "https://www.payson.se/PaySecure?token=#{response_hash['TOKEN']}"
elsif response_hash['responseEnvelope.ack'] == 'FAILURE'
  redirect_to @signup.event.home_path
end
This will redirect to Payson paysecure page. And client will complete the payment which will redirect the client back to returnUrl. If the client cancels the payment then he will be redirected to cancel url.

Step 3 (complete the process)

Now it is time to nail it ;)
In the return action you should check that the payment is done.
response = RestClient.get "https://api.payson.se/1.0/PaymentDetails?token=#{signup.payson_token}",
              {'PAYSON-SECURITY-USERID' => 'XXXX', 'PAYSON-SECURITY-PASSWORD' => 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'}
response_hash = parse_response(response)
@signup.payson_params = response_hash
@signup.payson_status = response_hash['responseEnvelope.status']
@signup.save!
if @signup.payson_status == Payment::PaysonClient::COMPLETED
  confirm_signup
else
  @signup.fail!
  ErrorNotifier.deliver_notification("Payment failed with status #{@signup.payson_status} for signup #{@signup.inspect}")
end
You can check the reference for pay details request here.

Saturday, August 8, 2009

Tips on writing browser compatible css

Writing browser compatible css is a difficult job for people with less experience in css. Specially Internet Explorer make things interesting(or gives you headache, what ever you prefer ;) ). As an application grows it becomes more and more difficult to manage browser compatibility. And as Internet explorer continues to release new versions, it leaves a few time for developers to spare. Some times different browser is needed to tweak differently. It may be the size of the font, padding floating problems etc.

People then started to use Conditional Comments like bellow to give browser compatibility,

<!--[if lte IE 6]>
<link rel="stylesheet" type="text/css" href="ie_hacks.css" />
<![endif]—>

And there is the !important hack

Normally in CSS whichever rule is specified last takes precedence. However if you use !important after a command then this CSS command will take precedence regardless of what appears after it. This is true for all browsers except IE. Here you can find more.

h1 { font-size: 1.6em !important; font-size: 1.4em; }

Here IE still takes 1.4em as the font size.

Tantek box model hack

Tantek introduced a hack for ie and opera regarding the box model problem.

Hybrid Hacking defined css as,

#wrapper {
width: 770px;
wid\th: 750px;
}

It's a legal 'escape' backslash and should be ignored, but when it is inside the property name it is not ignored by IE5 and IE5.5 for Windows. Instead it causes those browsers to ignore the following "t" character in this case, thus making the property name unreadable to them. Which was explained here.

Then there was the The Child and Adjacent Sibling Hacks, as IE does not understands html>body. Which looks like,

#wrapper {
min-height: 500px; /* IEwin does not support min-height */
height: 500px;
}

html>body #wrapper {
height: auto;
}

This is discussed more elaborately here.

Here is a list of rule compatibility of browsers which is really useful.

An easy solution to write css which can easily support different browser

It is a combination of Javascript and CSS. Here is the Javascript that detects the browser and add a dummy class to body tag.

if ( $.browser.msie && $.browser.version == "6.0" ) {
$("body").addClass("ie6");
}
Although it is written in JQuery, there are plain Javascript available.

So now if your clients browser is IE6 then you already have a dummy class added to you body tag. Now you can write IE6 specific hack easily.

h1 { font-size: 1.6em; }
.ie6 h1 { font-size: 1.4em; }

It is more readable and you can provide different hack for different browser and versions with this hack.

References

http://www.positioniseverything.net/articles/ie7-dehacker.html

http://www.evolt.org/ten-css-tricks-you-may-not-know

Thursday, August 6, 2009

Using acts_as_auditable for keeping history for model activities in rails

Keeping change history for important models are crucial for some application. And acts_as_auditable provides a clean implementation for keeping history.

Install

1. Download acts_as_auditable and put in your vendor folder

2. run

ruby script\generate audit

from your application directory. Which will generate a migration script to create audits table and a model named Audit.

Expectation

1. User model that inherits from ActiveRecord::Base with an instance method of auditor_name(it is required as it stores the auditors name as well as the auditor’s reference for keeping history).

2. A property named auditor(which will be injected in the model where you are using audit) should be prefilled with the user object who is changing the model.

3. Now you can use audit in your model as,

audit :when => :before_update,
      :if => lambda {|work_item| work_item.changed? },
      :with_message => lambda { |post| 'Something changed :)' }

Here

:when         => any active record callbacks (like :before_create)
:if           => provide a condition which will be checked to create the audit
:with_message => the message to be stored

Well that’s about it to use acts_as_auditable.

Implementing in real project

The challenge that I faced is to create a human readable message for model and make it maintainable.

I actually used audit like,

audit :when => :before_update,
      :if => lambda {|work_item| work_item.changed? },
      :with_message => lambda { |work_item| work_item.audit_message }

Now here is the code to generate the message.

def audit_message
  history_text = ''
  self.changes.each do |field, change|
    history_text += "#{field.humanize} changed from '#{change[0]}' to '#{change[1]}'\n" unless field.ends_with?('_id')
  end

  history_text += audit_message_for('project_id', Project, :name, 'project')
  history_text += audit_message_for('sprint_id', Sprint, :name, 'sprint')
  history_text += audit_message_for('responsible_person_id', User, :full_name, 'responsible_person', 'Responsible Person')
  history_text += audit_message_for('release_id', Release, :name, 'release')
  history_text += audit_message_for('point_id', Point, :name, 'point')

  return history_text
end

And here is the nasty part that at least cleans the audit message implementation. It helps to generate audit message for reference objects.

private
# Used for making the audit text readable
#
# ==== Parameters
#
# * +field+ - The database field to inspect changes
# * +klass+ - The class for the referenced object
# * +klass_property+ - The property of the object which will be readable to store audit data
# * +readable_name+ - readable name for the class. By default it is klass.to_s
#
# ==== Returns
# The audit text for that field.
# If there is no change in the field then empty string is returned
def audit_message_for(field, klass, klass_property, belongs_to, readable_name = klass.to_s)
  history_text = ''
  seperator = '\n'
  #as this is done with reflaction, catching exeptions for protection
  begin
    if self.send("#{field}_changed?")
      field_was = "#{field}_was"

      changed_from = klass.find(self.send(field_was)).send(klass_property) unless self.send(field_was) == nil
      changed_to   = self.send(belongs_to).send(klass_property) unless self.send(field) == nil

      if self.send(field_was) == nil
        history_text = "#{readable_name} assigned to '#{changed_to}'#{seperator}"
      elsif self.send(field) == nil
        history_text = "Removed #{readable_name} from '#{changed_from}'#{seperator}"
      else
        history_text = "#{readable_name} changed from '#{changed_from}' to '#{changed_to}'#{seperator}"
      end
    end
  rescue Exception => ex
    logger.error "Error #{ex.to_s}"
  end

  return history_text
end

Another thing to consider is assigning the auditor before saving the history. It is cleaner if you define a method named auditor. That is how you can avoid assigning to that attribute.

def auditor
  return self.new_record? ? self.creator : self.updator
end

But for implementing like this you need to modify some code in the library. Open the vendor\plugins\acts_as_auditable\lib\shooter\acts\auditable.rb and remove the line,

attr_accessor :auditor

Otherwise your method will be overwritten.

Sunday, July 26, 2009

Give partial test release and get early feedback

In scrumpad project we give our test rollout on Tuesday and production rollout on Wednesday(if every thing goes well :) ). But soon we realized that one day after test deployment is not enough to provide  a smooth production delivery, as we need to work on client feedback and issues after test rollout. This becomes a bigger issue if the client is in the opposite time zone, which gives us less time to communicate.

To resolve this issue we introduced partial test rollout with in the sprint, which helped us a big time. This way we get early feedback from client, which makes us more efficient in responding.

Benefits

  • Early feedback reduces risk on successful production delivery
  • Reduces the scope of communication gap between client and developers

Things to keep an eye on

  • With in the sprint the code base can be unstable. To resolve this we predefine a date for partial test deployment, so that people are prepared and commit only stable code on that day. Before test rollout we run all the test codes and always keep a sharp eye on the continuous integration report so that our code base is kept stable.
  • Be brave to give partial test rollout. Some functionality might break(so let the client be aware of this) but the early feedback will surely make your life easy :) . So iterate test deploy with in the iteration.

Thursday, July 23, 2009

Looking into rails named_scope

named scope?

Nick Kallen’s has_finder plugin has found it’s way into rails 2.x as named_scope. Named scope is all about scoping or narrowing the database query.

Let me go through an example to make things easy.

class Post < ActiveRecord::Base
  belongs_to :author,   :class_name => 'User'
  has_many   :comments, :dependent  => :destroy

  named_scope :published,   :conditions => { :is_published => true }
  named_scope :draft,       :conditions => { :is_published => false }
  named_scope :has_comment, :conditions => [ 'comments_count > 0' ]

  named_scope :recent,    lambda { |*date| {:conditions => { :created_at => date.first || 1.weeks.ago } } }
  named_scope :before,    lambda{ |date| { :conditions => ['created_at > ?',  date] } }
end
You can scope your query and make it more readable.
Post.published #equivalant to Post.all.published

You can also scope on finder methods like,

Post.find(:all, :conditions => { :created_at => 1.weeks.ago }).published

You can use finder on scope like,

Post.published.find(:all, :conditions => { :created_at => 1.weeks.ago })

Even scope on the relations.

class Comment < ActiveRecord::Base
  belongs_to :post
  belongs_to :author, :class_name => 'User'

  named_scope :unread, :conditions => {:is_unread => true}
  named_scope :read, :conditions => {:is_unread => false}
end

So now you can write like,

Post.find(id).comments.unread

Chaining

Now would not it be wonderful if you could write like “Get all posts which are recently published” and it would return you what it means.

Using named_scope that dream will come true ;). You can finally write code like this,

Post.recent.published

You can chain up to your hearts content ;). You can do all sort of combination like,

Post.recent.published.has_comment

Which will return you posts which are recently published and has comments. See how much readable the code has become.

Passing Arguments

You can pass arguments using lambda.

Post.published.before(1.days.ago)

Named Scope Extensions

Extend named scope and add methods to it.

class Post < ActiveRecord::Base
  named_scope :draft,       :conditions => { :is_published => false } do
    def publish
      each { |post| post.update_attribute(:is_published, true) }
    end
  end
end
Post.recent.draft.publish

This will find all recent draft posts and publish them.

Anonymous Scopes

Creating named scopes on the fly.

# Store named scopes
published = Post.scoped(:conditions => { :is_published => true })
recent    = Post.scoped(:conditions => { :created_at => 1.weeks.ago })

# Which can be combined
recent_published = recent.published

Why use named scope?

  • Increases readability
  • Reduces number of queries as it can be chained
  • Very helpful for dynamic queries(like using pagination or dynamic filter)

A common issue

Named scope is a class methods. And you should always be very careful for class methods. Here is an example where most people does it wrong.

class Post < ActiveRecord::Base
  belongs_to :author,   :class_name => 'User'
  has_many   :comments, :dependent  => :destroy
  
  named_scope :recent,  :conditions => { :created_at => 1.weeks.ago } 
end

Now I can call Post.recent and expect to get all Posts within one week. But in times you will find that this query is starting to give wrong results.

Why???!!!

Named scope is a class method and so 1.weeks.ago is evaluated when the class was loaded. Now it does not matter when you call the named scope it will always run the query with the same created_at date. We also made this mistake :( and learned from it :)

A lambda block is not evaluated when the class is loaded. So there is a work around it.

class Post < ActiveRecord::Base
  belongs_to :author,   :class_name => 'User'
  has_many   :comments, :dependent  => :destroy

  named_scope :recent,    lambda { |*date| {:conditions => { :created_at => date.first || 1.weeks.ago } } }
end

Taking the lambda input like this will give you flexibility of not providing the parameter at all. For now ruby does not provide facility to take default parameter for lambda.

Deep inside named scope

The implementation of Named scope is a beauty of rails. Although the result that named scope produces seems like an Array, but actually it is not an Array but a simulation of an Array. Calling a named scope over a finder object actually returns a ActiveRecord:NamedScope:Scope object. When we chain scopes on that object, appends the query logic in the scope object. The query is not evaluated until an Array method(like each, first, last) etc is called. And when these Array methods are called the scope object then evaluates the query and delegates the method which was called as an array to the real array that has been evaluated. Now you can not chain the scope any more, as it is already been evaluated. That is how the named scope magic works in ruby on rails.

Reference

http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality

http://railscasts.com/episodes/108-named-scope

http://apidock.com/rails/ActiveRecord/NamedScope/ClassMethods/named_scope

Friday, July 17, 2009

Some Css and Javascripts optimization tips

There are so many aspect for optimizing the performance of a web application, that some times people tends to forget about Javascript and Css.

Yahoo developers experienced that, 80% of the end-user response time is spent on the front-end. Most of the time browser is busy downloading images, stylesheets, scripts, Flash, etc. Here you can find the details.

But there are improvement opportunities in these areas to improve the over all performance of the application.

Mostly we concentrate on some basic criteria

  1. Caching
  2. Minifying Javascript and Css
  3. Reducing number of files

Caching

Caching is great and browser gives you for free :). But should all our css and Javascripts should be cached??

Actually no!! Because some times browsers cache too much(specially Internet Explorer). You want the client to get the latest files if the file is changed.

So we need to identify the files that changes and files that do not change(library files,  like jquery, prototype etc). We expect library files to get cached and custom files that changes a lot, not to be cached. We can skip caching by passing a random query string like,

<script type="text/javascript" src="scripts/default.js?rand=1"></script>
That random number can be generated from the server side while serving the page (which is a built in facility for rails).
Now for common libraries(jQuery, protopye) we should use Google API for 2 reasons
  1. It grabs the library from the closest location it can get. So it loads faster.
  2. It frees your server from serving the library file, so that your server can serve more files instead.
This is how you can use Google API to load popular Javascript libraries.
<script type="text/javascript" src="http://www.google.com/jsapi"></script><br /><script type="text/javascript"><br />  google.load("jquery", "1.3.2");<br /></script>

Minifying Javascript and Css

According to Yahoo!'s Exceptional Performance Team, 40% to 60% of Yahoo!'s users have an empty cache experience and about 20% of all page views are done with an empty cache (see this article by Tenni Theurer on the YUIBlog for more information on browser cache usage).

So surely you want to minify all your javascripts and css on your production server. There are some nice online Javascript and css packer which actually does the trick.

Javascript

http://jscompress.com/

http://dean.edwards.name/packer/

Css

http://www.cssoptimiser.com/

http://flumpcakes.co.uk/css/optimiser/

I know what you are thinking. You can’t go to web and pack all your css and Javascripts all the time you deploy, specially if you are following Agile and deploying your code after every 2 weeks.

There are platform specific implementations to resolve this problem. For rails we can use this to minify and pack javascripts and reduce number of Javascripts.

You can use yahoo compressor written in Java, so you can run that in any platform.

http://developer.yahoo.com/yui/compressor/#work

There is another implementation by Douglas Crockford,

http://crockford.com/javascript/jsmin

We can add necessary commands to our deployment script, so that after or before deployment the compressor is run.

Reducing number of files

Web servers can not serve a lot of files consecutively. There are limitation for browsers as well. If you watch your site with firebug net inspection, you will see that a lot of file calls which are not called parallely. So reduction in number of files served can improve the performance of the web application.

How can we reduce number of files?

There are several ways we can reduce number of files.

1. We can merged css and javascript the way we minified it.

2. Most of the cases we don’t care about the images. As a result the number of images grow rapidly.

There are some nice ways to merge images into one using css background-position property. People call this css sprite.

And every one use it to reduce file size as well as number of files.

If you merge some images into one, then size is actually reduced. Because other then the picture information every image maintains a color template. If some images are merged then a super set of color template is generated which reduces the total size of the image then the sum of the size of individuals.

Here are some nice examples

http://www.smashingmagazine.com/2009/04/27/the-mystery-of-css-sprites-techniques-tools-and-tutorials/

http://www.alistapart.com/articles/sprites

http://css-tricks.com/css-sprites/

Here is a site that generates css sprite.



Thursday, July 9, 2009

Rails logger configuration and log level in production environment

In production environment, it not feasible to use one log file forever. So people use log that rolls over, depending on file size or time etc.

If we want to roll over the log file, we can define our custom logger using the following code in the configuration(in config/environments/production.rb).

config.logger = Logger.new(config.log_path, 50, 5242880)
Here is the doc for instantiating Logger. The params are as follows.
Logger.new(name, shift_age = 7, shift_size = 1048576)<br />Logger.new(name, shift_age = 'weekly')
Another thing that we need to set for the production is the log level. We do not need to log the query generated by active record or logs that are in debug level. So we can define the log level as follows.
config.logger = Logger.new(config.log_path, 50, 5242880)<br />config.logger.level = Logger::INFO
But if you are using the default log which rails offers by default, you can set the log level as,
config.log_level = :info
You can find the rails environment configuration cheat sheet here.

Wednesday, July 8, 2009

Some of the useful way of using fixture better

1. Using new fixture facilities in rails 2.(example)

    Which will remove the relational fixtures for has_many :through and has_and_belongs_to_many relations.

    It will remove the ids and will give a better way of relating between tables.

2. Fixtures are read only:    Never modify any existing fixture, unless your database schema has changed.    Which also indicates that we should be very careful when are adding a new fixture.

3. Another way to identify if the fixture is well written is that they all should be meaningful.    And none of them should look similar.

   If a different fixture is needed for only 1 or 2 test, then update existing before doing the test.    For an example,

should 'assign responsible person to unassigned task' do
    task = tasks(:task_not_started)
    task.users.clear #clear the existing fixture(not creating a new one for that fixture) 

    assign_and_assert_responsible_person(task, users(:login_user))
end
This will reduce the number of fixture set and keep them clean.

4. Often we write test codes that involves a lot of fixture.    Some times when we get test fail, we run through the fixtures, trying to find out which went wrong.    But instead if we comment our code such a way that the fixture is understood from the test code,    then that would be even better. Like,

context 'in progress task' do
  setup do
    @task = tasks(:task_in_progress)
    # task -> time_estimates
    #         [ user: login_user, hours_spent: 2, hours_remaining: 8, entry_date: 1.days.ago ]
    #         [ user: developer , hours_spent: 4, hours_remaining: 3, entry_date: Date.today ]
  end

  should 'return hours spent upto' do
    assert_equal(2, @task.hours_spent_upto(1.days.ago))
    assert_equal(6, @task.hours_spent_upto(Date.today))
  end
end
5. Inherit fields, that are less likely to be different for each fixture
backlog_item: &common_backlog_fields
  project_id: scrumpad
  type: Story

bug:
  <<: *common_backlog_fields
  type: Bug
  title: Test Bug
  content: Bug content
  created_at: <%= 10.days.ago.to_s(:db) %>
  updated_at: <%= 3.days.ago.to_s(:db) %>

story:
  <<: *common_backlog_fields
  title: Sample story
  state: <%= WorkItem::COMPLETED %>
  created_at: <%= 10.days.ago.to_s(:db) %>
  updated_at: <%= 2.days.ago.to_s(:db) %>
Here we can define the common required fields in backlog_item and use that definition for other fixtures. The fields can be overwritten by redefining in the fixtures as we did overwritten type for bug.

Friday, May 22, 2009

Selenium In Rails with Fixtures

Selenium is a framework for acceptance testing, designed for web applications. With selenium you can run your tests on all popular browsers.

Now a days web applications are consist of a lot of UI logic, animations, ajax calls. Only unit test and functional test does not ensure the stability of your application any more. A small change in Javascript can cause instability in your application. Tiny changes can break the contract of browser compatibility. A simple miss spelled link can give you a nightmare.

Selenium gives you the power to run automated acceptance test codes in real browsers. As it supports all popular browsers you can easily test browser compatibility of your application.

Key Features

  • Selenium IDE provides facility to record test script with ease and export the script to your preferred language(Java, C#, ruby, Perl, PHP etc)
  • Write one test script and run in all popular browsers and OS
  • Selenium Grid facilitates to run test codes parallely in multiple server, which pace up the execution of test code.

Setup

Install Selenium client

gem install selenium-client

Download Selenium Remote Control from here.

You will need Java installed on your machine to run Selenium Remote Control.

I write a script to start Selenium Remote Control, which is like.

cd E:\selenium\selenium-remote-control-1.0-beta-2\selenium-server-1.0-beta-2
java -jar selenium-server.jar

Use Firefox and Selenium IDE(a Firefox plugin) to capture the actions and convert it to ruby code.

XPath Checker and Fire Finder are two useful Firefox plugin to find and locate elements using xpath.

Record actions

Start Firefox, go to the root url, from where you are going to start test. Go to tools tab and start Selenium IDE.

Now as you browse through the site Selenium IDE will record the actions. After you have finished a scenario, you can stop recording and export test case as ruby file from File menu.

Selenium IDE generates is an old rails style code and it uses old selenium client driver. Here is a sample integration code that uses rails 2.3.2 style and new selenium client driver.Now to run your test code as you have noticed, you need mention the root url of the site you are testing.

require 'test_helper'
require 'selenium/client'

class PostsIntegrationTest < ActionController::IntegrationTest
fixtures :all

def setup
@browser = Selenium::Client::Driver.new(
:host => "localhost",
:port => 4444,
:browser => "*firefox",
:url => "http://localhost:3000",
:timeout_in_second => 60
)

@browser.start_new_browser_session
end

def teardown
@browser.close_current_browser_session
end

test 'the truth' do
@browser.open "/posts"
@browser.click "link=New post", :wait_for => :page
@browser.type "post_title", "test"
@browser.type "post_title", "Testing with Selenium"
@browser.type "post_body", "bla... bla..."
@browser.click "post_published"
@browser.click "post_submit", :wait_for => :page
assert_equal "Testing with Selenium", @browser.get_text("xpath=/html/body/p[2]/span")
end

end
Here is the trick. Run your application in test environment. So the application will use test database. As test database is prepared automatically by rails, you can use the test fixtures as the input set of you test codes. And it will be automatically reset to the fixture set for each test methods.

How to organize

1. Dry and reuse

Acceptance test codes are directly dependent on view code. So you need to reuse test codes as much as possible. If you don’t a simple change in view will make you life hell.

2. Separate your actions to methods, so that you can reuse

def login(user_name, password)
@browser.open "/"
@browser.type "user_name", user_name
@browser.type "password", password
@browser.click "css=.btn[name='commit']", :wait_for => :page
end

def login_as_developer()
login(users(:developer).user_name, '123')
end

Now you can call login method to login to the system. And do not put assertions in these methods. This way you can even test the failure path.

3. Now call these basic methods and do assertion. This will make your code readable.

test 'login as a developer with valid credential' do
login_as_developer()
assert_url('/dashboard/show')
end

Note: Well there is no such thing as assert_url in selenium client to assert the current relative url.You can copy the following code and put it in your test helper.

def assert_url(url)
assert_equal(url, @browser.get_location().match(/.+\/\/[^\/]+(.*)/)[1])
end

4. Use a different helper file for common methods. Don’t use the common test helper, as selenium test are quit different from unit and functional test of rails.

It does not uses mock request and response. So you can not use selenium methods else where. That is why it is better to separate the selenium test helper.

5. Use selenium-client, so that you can use different wait_for methods, which are very useful. See the documentation here.

Tuesday, May 12, 2009

A solution for a gem install mysql problem

Some times we get an error in linux as follows while running gem install mysql,

root@ip-10-251-30-82:/etc/mysql# gem install mysql
Building native extensions.  This could take a while...
ERROR:  Error installing mysql:
     ERROR: Failed to build gem native extension.

/usr/bin/ruby1.8 extconf.rb install mysql
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lm... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lz... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lsocket... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lnsl... yes
checking for mysql_query() in -lmysqlclient... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
     --with-opt-dir
     --without-opt-dir
     --with-opt-include
     --without-opt-include=${opt-dir}/include
     --with-opt-lib
     --without-opt-lib=${opt-dir}/lib
     --with-make-prog
     --without-make-prog
     --srcdir=.
     --curdir
     --ruby=/usr/bin/ruby1.8
     --with-mysql-config
     --without-mysql-config
     --with-mysql-dir
     --without-mysql-dir
     --with-mysql-include
     --without-mysql-include=${mysql-dir}/include
     --with-mysql-lib
     --without-mysql-lib=${mysql-dir}/lib
     --with-mysqlclientlib
     --without-mysqlclientlib
     --with-mlib
     --without-mlib
     --with-mysqlclientlib
     --without-mysqlclientlib
     --with-zlib
     --without-zlib
     --with-mysqlclientlib
     --without-mysqlclientlib
     --with-socketlib
     --without-socketlib
     --with-mysqlclientlib
     --without-mysqlclientlib
     --with-nsllib
     --without-nsllib
     --with-mysqlclientlib
     --without-mysqlclientlib


Gem files will remain installed in /usr/lib/ruby/gems/1.8/gems/mysql-2.7 for inspection.
Results logged to /usr/lib/ruby/gems/1.8/gems/mysql-2.7/gem_make.out
root@ip-10-251-30-82:/etc/mysql# gem install mysql -- --with-mysql-config=/etc/mysql/my.cnf
Building native extensions.  This could take a while...
ERROR:  Error installing mysql:
     ERROR: Failed to build gem native extension.

The solution is simple :)

Just run,

apt-get install libmysqlclient15-dev libmysqlclient15off zlib1g-dev libmysql-ruby1.8

Run the following if you do not have mysql installed,

apt-get install mysql-server-5.0 mysql-client-5.0 libmysqlclient15-dev libmysqlclient15off zlib1g-dev libmysql-ruby1.8

And then run

gem install mysql

Saturday, May 2, 2009

Testing model in rails

How we want our test environment

  1. Isolation of input fixtures, so that changing fixture of one test code will not impact others.
  2. Easily create input set and reuse existing.
  3. Readable test code.
  4. Runs very fast(Slower test codes are run less by developers).
  5. Write less to test.

Problems with built in fixture and test helper

  1. Fixture does not allow to isolate input set.
  2. No feature of reusability in fixtures causes developer to create unnecessary duplication in fixtures.
  3. Changes in table definition causes a lot of change in fixture set.
  4. Fixtures are hidden in different file. So it becomes difficult to trace a test code.
  5. Fixture is database driven. So even if you do not need a saved instance of an ActiveRecord object, you end up using one. The more the queries get executed, the slower the test code becomes.

Factory girl, one of the alternate of fixture seems to be the better solution then fixture. And shoulda makes the life easier for writing test codes.

Why factory?

  1. Isolated input set
  2. Different build method gives the flexibility to create saved and unsaved instances
  3. Can easily extend existing factory to create a new one
  4. Facility to override property and to stub methods to reduce database query
  5. Increase readability of test codes.

Why Shoulda?

  1. Context & Should blocks - Context and should block provides facilities to do BDD
  2. Assertions - Provides many common and useful assertions
  3. Macros - Generate many ActionController and ActiveRecord tests with helpful error messages

So let’s get some action. Here is a simple test done using factory and shoulda. We will write unit test for User model which looks like the following.

class User < ActiveRecord::Base
 has_many :posts, :order => 'created_at DESC'
 has_many :comments

 validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
 validates_uniqueness_of :email

 def display_name
   return "#{first_name} #{last_name}"
 end

 def latest_post
   return self.posts.first
 end
end

The Post model is,

class Post < ActiveRecord::Base
 belongs_to :user
 has_many :comments, :dependent => :destroy

 validates_presence_of :title
 validates_presence_of :body
end

And the user factory is,

Factory.sequence :email do |n|
 "email#{n}@test.com"
end

Factory.define :user do |u|
 u.first_name 'Ashraf'
 u.last_name  'Zaman'
 #allows you to create different users with different email using the same definition
 u.email { Factory.next(:email) }
end

Post factory is,

Factory.define :post do |p|
 p.title 'A sample post'
 p.body  'This is a sample post'
 p.created_at Time.now
 p.updated_at Time.now
end

Finally the user model test is,

require 'test_helper'

class UserTest < ActiveSupport::TestCase

 should_have_many :posts
 should_have_many :comments
 should_require_unique_attributes :email

 should_not_allow_values_for :email, "ab.cd", "1234@"
 should_allow_values_for :email, "ashrafuzzaman.g2@gmail.com"

 should 'display_name' do
   user = Factory.build(:user, :first_name => 'Ashraf', :last_name => 'Zaman')
   assert_equal('Ashraf Zaman', user.display_name)
 end

 context 'Default posts' do
   setup do
     @user = Factory.build(:user, :posts => [
         Factory.build(:post, :title => 'Second Post', :created_at => Time.now),
         Factory.build(:post, :title => 'First Post', :created_at => 2.minutes.ago)
       ])
   end

   should 'return latest post' do
     assert_equal('Second Post', @user.latest_post.title)
   end
 end

end

You can download the demo from here

How factory helped

To test the display_name I do not need a saved instance, So I used Factory.build to build the model object with out saving it in the database.

Note: With Factory.build you can create an unsaved model instance from the factory prototype. It is very useful for testing model logic.

Some attributes of user prototype are intentionally redefined to increase the readability of the test code. Now you can easily read the test code as you can see the input set right in front of you. Thus you can effortlessly create different input set from one basic prototype.

The interesting part of this section is the test of latest_post of user model. Here as you can see the association method ‘posts’ is overridden with expected post list. Now you can mock this this methods as this is provided by the framework itself. So no need to test it. But by mocking this you actually increased the readability of the test code and avoided database call.

How shoulda helped

The Shoulda gem makes it easy to write elegant, understandable, and maintainable Ruby tests. Shoulda consists of test macros, assertions, and helpers added on to the Test::Unit framework.

With shoulda we defined a context 'Default posts' and initialized it. We can test codes related to posts with in the context. As the context is setup with the minimum and sufficient information of input set needed for the context, the test code becomes very simple and easy to read and maintain.

Resources

http://thoughtbot.com/projects/factory_girl

http://thoughtbot.com/projects/shoulda

Thursday, April 30, 2009

Create Image from existing instance and reuse to create a new instance

Often we need to create one production instance and another test instance for testing. Environment is similar for both instances. So if you are using Amazon ec2 then you can configure one instance and then create an image from that instance to reuse it to create another instance just like the first one.

Create volume from your instance

Copy pk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.pem and cert-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.pem file into /mnt folder in your instance.

Note: You can download these files from your amazon account.

/mnt is not included in the image so your certification files will be secured and not stored in the image.

login to your instance and run in command line,

ec2-bundle-vol -d /mnt -k /mnt/pk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.pem -c /mnt/cert-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.pem -u xxxxxxxxxxxx -r i386 -s 1536
Here,
–d => is the directory where the images will be generated
-k => privatekey PATH
-c => cert PATH
-u => your AWS account ID as your username (not your AWS Access Key ID)
-r => Specify target architecture. [i386, x86_64]
-s => The size, in MB (1024 * 1024 bytes), of the image file to create. The maximum size is 10240 MB
upload bundle into your s3 bucket

Then run,

ec2-upload-bundle -b 'your-s3-bucket' -m /mnt/image.manifest.xml -a 'aws-access-key-id' -s 'aws-secret-access-key' 
Register image

run

ec2-register 'your-s3-bucket'/image.manifest.xml

You should see some thing like this in the screen.

IMAGE   ami-xxxxxxxx

Note: You might not get this command from instance. For this you will need ec2 api tool in you instance or in your local machine.

You can download it from here.

Running Instances from your newly created image

run

ec2-run-instances ami-xxxxxxxx

You should see some thing like this in the screen.

RESERVATION     r-632db90a      106811649921    default
INSTANCE        i-xxxxxxxx      ami-xxxxxxxx                    pending
0               m1.small        2009-04-30T05:26:38+0000        us-east-1c

resources

http://docs.amazonwebservices.com/AmazonEC2/gsg/2006-06-26/creating-an-image.html

http://developer.amazonwebservices.com/connect/entry.jspa?externalID=351

http://wiki.apache.org/hadoop/AmazonEC2[For publishing Image as public]

Monday, April 27, 2009

Using webrat for integration testing

What is webrat

Webrat lets you quickly write expressive and robust acceptance tests for a rails application.

How Webrat is different from default rails integration test

1. Rails default integration testing is nothing more than a series of functional tests. But in webrat you can actually do actions in pages. Here is a scenario for login.

visit('/')
fill_in('email', :with => user.email)
fill_in('password', :with => '1234')
click_button('login')

2. With webrat you can test user experience by filling in the text boxes, clicking the buttons etc.

3. Use webrat API for Browser Simulator and real Selenium tests using Webrat::Selenium when necessary (eg. for testing AJAX interactions).

4. Supports popular test frameworks: RSpec, Cucumber, Test::Unit and Shoulda

Installing webrat

gem install nokogiri
gem install webrat

In test_helper.rb add,

require "webrat"

Webrat.configure do |config|
 config.mode = :rails
end

For more information please visit http://github.com/brynary/webrat/tree/master

Some Tips

You can check something like, if your desired dropdown select option is currently selected or not using assert_select.

Let me show you the expected html to test

<select name="user[user_type_id]" id="user_user_type_id">
 <option selected="selected" value="1">Shipper</option>
 <option value="2">Transporter</option>
</select>

Here we want to test of Shipper is selected or not.

So the test code can be

test 'signup form with shipper' do
 visit('/')
 click_link('Signup as Shipper')
 assert_selected_option('user_user_type_id', 'Shipper')
end

def assert_selected_option(select_id, selected_text)
 assert_select("##{select_id} option[selected=selected]", selected_text)
end

This is how you can test contents of html.

Resources

http://github.com/brynary/webrat/tree/master

http://www.slideshare.net/brynary/webrat-rails-acceptance-testing-evolved

http://cheat.errtheblog.com/s/webrat/

Sunday, April 26, 2009

Rails route sequence

For a large RESTful rails project routes can become very complicated and a single controller can be accessed under different resources.

In rails 2.3.2 route sequence is important. Let me give a scenario,

map.resources :shippers, :shallow => true do |shipper|
 shipper.resources :jobs, :member => {:publish => :put} do |job|
 end
end

map.resources :jobs, :collection => {:open_jobs => :get}

This will generate routes as follows(by running rake routes)

job             GET    /jobs/:id(.:format)          {:action=>"show", :controller=>"jobs"}
open_jobs_jobs  GET    /jobs/open_jobs(.:format)    {:action=>"open_jobs", :controller=>"jobs"}

As in route.rb file /job/:id route path is defined first, when you will hit /jobs/open_jobs you will be mapped to {:action=>"show", :controller=>"jobs",:id=>"open_jobs"}

Then when I moved the open_job route definition up before the job resource under shipper, and it worked.

And now /jobs/open_jobs was mapped to {:action=>"open_jobs", :controller=>"jobs"}. So the resource definition is now like,

map.resources :jobs, :collection => {:open_jobs => :get}

map.resources :shippers, :shallow => true do |shipper|
 shipper.resources :jobs, :member => {:publish => :put} do |job|
 end
end

Reordering the sequence resolved that routing issue.

Friday, April 24, 2009

Use Migration Helpers to ease your migration script

One of the purpose of rails migration script was to wrap SQL with simple ruby code. But still we need some SQL for creating foreign key or inserting some default data or updating some existing data. There is a rails plugin to solve this problem.migration_helpers provides some basic helpers for writing migration scripts.

It wraps

  1. Add/remove foreign key
  2. Insert statements
  3. update statements

Here is a sample migration that uses insert and update statement.

class CreatePosts < ActiveRecord::Migration
    def self.up
      create_table :posts do |t|
        t.string :title
        t.text :body
        t.boolean :published
    
        t.timestamps
      end
    
      insert_row('posts', :title => 'Dummy Title', :body => 'A sample post', :published => false)
      update_row('posts', :set => { :published => true }, :where => { :title => 'Dummy Title' })
    end
    
    def self.down
      drop_table :posts
    end
end
And here is a sample migration that uses foreign key reference.
class CreateComments < ActiveRecord::Migration<br />    def self.up<br />      create_table :comments do |t|<br />        t.text :body<br />        t.boolean :published<br />        t.references :post<br />    <br />        t.timestamps<br />      end<br />    <br />      add_foreign_key('comments', 'post_id', 'posts')<br />    end<br />    <br />    def self.down<br />      remove_foreign_key('comments', 'posts')<br />      drop_table :comments<br />    end<br />end

Caution:

This is really a nice plugin but I needed to modify some code to work remove_foreign_key.

In plugins/migration_helpers/lib/migration_helpers_tasks.rb file replace the remove_foreign_key with the following code

def remove_foreign_key(table, target_table, constraint_name="#{table.to_s}_#{target_table.to_s}_fkey")<br />    execute "ALTER TABLE #{table.to_s} DROP FOREIGN KEY #{constraint_name};"<br />    execute "ALTER TABLE #{table.to_s} DROP KEY #{constraint_name};"<br />end
Reference:

http://github.com/patientslikeme/migration_helpers/tree/master



Thursday, April 23, 2009

Transaction in rails 2.3.2

In rails when we want some series of tasks to be atomic we use transaction. But how should we write our code to support transaction?

Let me explain how transaction in rails works. If any code inside a transaction raises an exception

  1. the transaction block rescues it
  2. rolls back the database and
  3. re throws the exception

So we need to make sure that statements that are not complete, raise exception. Here are some scenarios with explanation.

For all the scenarios the Comment model is like,

class Comment < ActiveRecord::Base
  belongs_to :post
  validates_presence_of :body
end

As model.collection << child_model does not raises exception the post is saved, as the transaction is unaware of the data save failure.

test 'transaction should not rollback transaction with collection create method' do<br />  is_comment_saved = false<br />  Post.transaction do<br />    post = Post.new({:title=> 'Test title', :body => 'A sample post', :published => true})<br />    post.save!<br />    is_comment_saved = post.comments << Comment.new({:published => true})<br />    #Comment with out body should be not saved for validation<br />    #but this does not raise exception so the transaction is not rolled back<br />    #I know that rails convention is that you first assign the comment and then save post<br />    #But there might be situation when you might want to save model which is unrelated to post in the same transaction<br />  end<br /><br />  assert_equal(1, Post.count)<br />  assert_equal(0, Comment.count)<br />  assert_equal(false, is_comment_saved)<br />end

To support transaction we need to write some thing like this,

test 'transaction should rollback transaction with throwing exception manually' do<br />  is_comment_saved = false<br />  begin<br />    Post.transaction do<br />      post = Post.new({:title=> 'Test title', :body => 'A sample post', :published => true})<br />      post.save!<br />      #Comment with out body should be not saved for validation<br />      raise Exception unless post.comments << Comment.new({:published => true})<br />    end<br />  rescue Exception<br />  end<br /><br />  assert_equal(0, Post.count)<br />  assert_equal(0, Comment.count)<br />  assert_equal(false, is_comment_saved)<br />end

model.collection << returns false the operation fails. So raising an exception while it returns false causes the transaction to rollback.

Let me give you a scenario with nested transaction.

test 'default Nested transaction should rollback with raising Exception' do<br />  begin<br />    Post.transaction do<br />      post = Post.new({:title=> 'Test title', :body => 'A sample post', :published => true})<br />      post.save!<br />      Comment.transaction(:requires_new => true) do<br />        post.comments.create({:body => 'A sample comment', :published => true})<br />        raise Exception<br />      end<br />    end<br />  rescue Exception => error<br />  end<br /><br />  assert_equal(0, Post.count)<br />  assert_equal(0, Comment.count)<br />end

Note: For nested transaction in rails 2.3.2 by default any transaction inherits the transaction of it’s parent transaction. To make a new child transaction you need to pass “:requires_new => true” as the parameter of transaction method.

Identical to single transaction nested transaction behaves same if you throw an exception. So if you really mean to use a child transaction, you will need to handle exception inside or around the child transaction.

The above example behaves same even if we do not use “:requires_new => true” for child transaction. now If you want to break the child transaction and not to interfere the parent transaction, you can use “ActiveRecord::Rollback”.

Transaction relays all the exception except ActiveRecord::Rollback. If you raise ActiveRecord::Rollback then the steps are

  1. the transaction block rescues it
  2. rolls back the database and
  3. DOES NOT re throw the exception

Here is an example,

test 'nested transaction should not rollback parent transaction that throws ActiveRecord Rollback in child transaction' do<br />  begin<br />    Post.transaction do<br />      post = Post.new({:title=> 'Test title', :body => 'A sample post', :published => true})<br />      post.save!<br />      Comment.transaction(:requires_new => true) do<br />        comment = Comment.new({:body => 'Test', :published => true, :post_id => post.id})<br />        comment.save!<br />        raise ActiveRecord::Rollback<br />      end<br />    end<br />  rescue Exception<br />  end<br />  assert_equal(1, Post.count)<br />  assert_equal(0, Comment.count)<br />end

In rails 2.3.2 ActiveRecord::Rollback does not work for child transaction that is not defined as :requires_new => true.

Here is another scenario for that test,

test 'default nested transaction should not rollback even child trasnsaction that throws exception in child transaction' do<br />  Post.transaction do<br />    post = Post.new({:title=> 'Test title', :body => 'A sample post', :published => true})<br />    post.save!<br />    Comment.transaction do<br />      comment = Comment.new({:body => 'Test', :published => true, :post_id => post.id})<br />      comment.save!<br />      raise ActiveRecord::Rollback<br />    end<br />  end<br />  assert_equal(1, Post.count)<br />  #Here comment is saved too<br />  assert_equal(1, Comment.count)<br />end

As you can see raising ActiveRecord::Rollback does not impact the result.

These are some of the scenario explained, which should help you to choose appropriate way to use transaction for your application.

You can download the test project from here.



Add custom rake task in your rails project

It is very easy to create a custom rake task in rails. We can often use this feature to ease our daily work. Recently I needed to run a cron job for a rails project, which is the perfect place for a custom rake task. You can follow these process to create a task.

1. Create a rake file as your_tasks.rake and put it in project_path\lib\tasks\

rails detects task from project_path\lib\tasks\

2. A sample rake task

task :start do
  #do some magic and start the cron
end
task :stop do
  #do some more magic and stop IT
end

3. Now run in command prompt from the project folder as

rake start

To make your tasks more meaningful you might want to try giving namespaces and a little description which explains the task a bit.

Here the simple modification you need

Rake task

namespace :cron do
  desc "Starts cron job"
  task :start do
    #do some magic and start the cron
  end
  desc "Stops cron job"
  task :stop do
    #do some more magic and stop IT
  end
end

Calling tasks

rake cron:start

Rake gives us the flexibility of defining dependent tasks so that the dependent tasks can be executed first.

Often we may need our rails environment to load before we do any thing. You can do it by

namespace :cron do
  desc "Starts cron job"
  task(:start => :environment)do
    #do some magic and start the cron
  end
  desc "Stops cron job"
  task(:stop => :environment)do
    #do some more magic and stop IT
  end
end

Now when you will run the task, you will find that your environment is now loaded.

Resource:

http://www.railsenvy.com/2007/6/11/ruby-on-rails-rake-tutorial

http://rake.rubyforge.org/

http://martinfowler.com/articles/rake.html

Monday, April 13, 2009

DateTime with zone support in rails fixture

To get time with zone support we usually call, Time.now.utc

But if we use Time.now.utc in fixture like,

fixture1:
deadline: <%= Time.now.utc %>

It gives an error:

ActiveRecord::StatementInvalid: Mysql::Error: Incorrect datetime value: 'Sun Apr 12 11:40:05 UTC 2009' for column 'deadline' at row 1: INSERT INTO job_assignments (job_id, updated_at, id, deadline, transporter_fee, transporter_id, created_at, state) VALUES (245383586, '2009-04-12 09:40:07', 809788707, 'Sun Apr 12 11:40:05 UTC 2009', 75, 468814034, '2009-04-12 09:40:07', 'assigned')

Because fixtures calls a default to_s function for each fields to create the insert script. Fixtures does not save records through Models. Time.now.utc.to_s generates a string which is not in the format to save date time in mysql. To generate such format we need to call Time.now.utc.to_s(:db). So the fixture turned out like,

fixture1:
deadline: <%= Time.now.utc.to_s(:db) %>

Sunday, February 1, 2009

Png Corner is the solution of rounded/styled corners which is browser compatible

I was searching for an easy and simple implementation of smooth rounded corner that is browser compatible. If you want smooth corners you will need png images and Internet Explorer 6 has issues with png alpha transparency. Then I came with a project pngcorner . This is very easy to use and very small in size(less than 4 kb ). You can download the demo from here.

For png transparency I used unitpngfix , a very small(less than 1 kb ) and yet very effective javascript library. And used a table structure rounded corner template. For detail please visit the project page.

Here is a demo and here is the demo with jquery plugin.

Why use png corners

  1. It is browser compatible(works in IE 6/7, FireFox 3, Opera 9, Chrome 1.x)
  2. It's small(less than 4 kb )
  3. Easy to use(Just follow 3 easy steps)
  4. Can use png transparency feature so that you can create your own styled box.
  5. Same behavior across browsers
  6. Size of your content is totally flexible
  7. You can change images from css
Why special
There are a lot of implementation on rounded corner. And there are simpler implementation.
But if you need smooth(using png images), transparent(that works even in IE6), browser compatible, small(less than 4kb), with flexible content dimension(content can have any dimension) you should use pngcorners.
Places to use
  1. Use to create smooth rounded corner content with shades
  2. Use to create buttons with shades(as the size is expandable you can have small buttons as well as long ones)

Limitations

  1. It uses table for the structure of rounded corner. So your rounded corner is not as flexible as div layout (It is a small sacrifice for IE 6 png transparency)
  2. The images at left, right, top and bottom will be scaled not repeated. As Microsoft.Alpha filter do not support repeating.

Usage

1. Add png _corner. css in page

2. Add html structure for rounded corner, which looks like this,

<table class="rounded_corner" border="0" cellpadding="0" cellspacing="0">
  <tr><td class="top_left"/><td class="top"/><td class="top_right"/> </tr>
  <tr><td class="left"/>
    <td class="content">The content goes here :)</td>
    <td class="right"/>
  </tr>
  <tr><td class="bottom_left"/><td class="bottom"/><td class="bottom_right"/></tr>
</table>

3. Add png hack css in header as shown bellow so that the script is only added for Internet Explorer 6.

4. Add clear. gif in root_file/images

And you should be good to go :)

jQuery Version

There is a jQuery version of png corners. For that you will have to follow all the steps and add another javascript file pngcorners.js. But now the step 2 is now being simplified.

No need to remember all those tags and make your view complex. Just call,

$(".round_me").pngcorner();

Where you are expecting for elements with round_me class name will become rounded corner :)

So it reduces tags and cleans the view a bit.

Caution

When you load you content from ajax call or create your content dynamically after your page is loaded then you have to call the following javascript after you have done loading your content.

pngfix();

I am still searching for a solution with lesser limitation and complexity. So any suggestion is welcome.

Sunday, January 11, 2009

Test rails with Mocha

Rails is a framework that came up with facilities for testing using fixtures. Testing using  fixture is a nice feature to have for a small project. But as the project grows some problems might be seen. Like,

  1. Difficult to manage fixture
  2. Takes long time to run the test

Difficult to manage fixture:

As it becomes hard to manage fixtures, people tends to add and do not intend to reuse existing, as that might break current test codes.

So the number of the entry in fixtures increase day by day. Eventually it becomes unmanageable.

Takes long time to run the test:

As fixture driven testing takes a lot time to run the test. People don't feel comfortable to run test for a large project. Even running one test file sometime takes 2/3 minutes. We use Continuous Integration(CI) to run test for the whole project in different server, while we do our regular tasks. But even that is not working out for us right now. Because, It takes about 30 minutes to test the whole project. CI looks up in repository and check for changes and if found any, it starts to build and run test. So If any code is checked in with in with in 30 minutes while the build is not completed, then that build goes into queue. And eventually we get the email notification from CI after 1/2 hours. Which is not satisfying the purpose of CI.

Solution:

I read about Mocha and really got interested. It is a solution to fixtures. You can use mock object to replace fixtures. At first I was confused about how should I mock my model objects. As it contains the business logic as well as the logic to save in database. Mocha gives you a solution as it gives facility to overwrite methods for an object without writing a real class. So you can mock save or find method of ActiveRecord and replace it with mock method with out creating a class. You can even mock a private method. Here is an example.

Wednesday, January 7, 2009

Replacing Prototype with jQuery in Rails

jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development.

For people who like to use jQuery in rails there is a  good news. There is a plugin jRails, which overwrites remote tags provided by rails and uses jQuery ajax call. You can find the project here.

jRails covers all of the functionality in the built in Rails prototype_helper as well as some of the functionality in scriptaculous_helper. Current release includes support for basic AJAX calls (form_to_remote, link_to_remote), RJS, observers (observe_form, observe_field) as well as a limited set of functionality for draggables, droppables, sortables and visual effects.

 

Resources:

jQuery home page

jRails plugin

jRails project page

http://justtalkaboutweb.com/2008/01/14/replace-prototype-with-jquery-on-rails/

Era of Multiprotocol Instant Messenger

Now a days people have at least 2 email accounts and most of the accounts are from different provider. When I am in my office I use gtalk for office account and yahoo messenger for my personal account. Open emails in gmail and yahoo. And might open facebook or any social networking sites. But now digsby has reduced much of these work. In one login to digsby I can login to messenger for gmail, yahoo or even facebook and more. See mail titles of various accounts and facebook feeds. And it is very intuitive and customizable.