March 7, 2012
Avoiding infinite loops using Recursion Guard

Let us say we have an invoice management system. When an invoice is approved, the system creates a payment directive. Upon successfully creating the payment directive, the system requests a 3rd party gateway to schedule a payment to the invoiced vendor. Upon successful scheduling the payment, the system saves the payment confirmation code returned by the gateway with the payment directive.

class PaymentDirective < ActiveRecord::Base

  after_save :schedule_payment

  def schedule_payment    
    update_attribute(:confirmation_code, GateWay.schedule(...))
  end

end 

The code above will result in an infinite loop(gulp) as the after_save callback is called upon updating the confirmation_code. We can address this issue by adding a guard variable inside the method to store the state of an on going method invocation

def schedule_payment
  return true if @schedule_payment_in_progresss
  @schedule_payment_in_progresss = true

  update_attribute(:confirmation_code, GateWay.schedule(...))

ensure
  @schedule_payment_in_progresss = false
end

Now the code looses the readability. To address this issue, I implemented the recursion guard as an aspect.

def schedule_payment    
  update_attribute(:confirmation_code, GateWay.schedule(...))
end        
recursion_guard :schedule_payment

I monkey patched the ActiveRecord class in a file called initializers/monkey_patches.rb.

class ActiveRecord::Base

  def self.recursion_guard(method, on_guard_return_value=true)
    old_method = instance_method(method)
    define_method(method) do |*args|
      begin
        return on_guard_return_value if (instance_variable_get("@recursion_guard_for_#{method}") == true)
        instance_variable_set("@recursion_guard_for_#{method}", true)
        old_method.bind(self).call(*args)
      ensure
        instance_variable_set("@recursion_guard_for_#{method}", false)
      end
    end
  end

end

December 1, 2011
Instructions for migrating from shared database to dedicated database on Heroku

Before you start the migration please be aware of these facts:

  • Heroku doesn’t migrate the data from the shared database to the dedicated database automatically.
  • Heroku doesn’t assign the dedicated database as the primary database automatically.
  • Heroku doesn’t remove the shared database even after you complete the migration. You have to remove it manually. Otherwise you will continue to incur charges(if any) for the shared database.

Instructions

  • Add the dedicated database to your application:

    $ heroku addons:add heroku-postgresql:ronin
    -----> Adding heroku-postgresql to sushi... done, v69 ($200/mo)
           Attached as HEROKU_POSTGRESQL_RED
    -----> The database should be available in 5-15 minutes
           Use `heroku pg:wait` to track status
    
  • Track the progress of the database creation:

    $ heroku pg:wait 
    Waiting for database HEROKU_POSTGRESQL_RED... done       
    
  • Get the connection credentials of the newly created database

    $ heroku pg:info
    
    === HEROKU_POSTGRESQL_BLACK
    Plan         Ronin
    Status       available
    Data Size    5.1 MB
    Tables       0
    PG Version   9.0.5
    Created      2011-10-10 17:59 UTC
    Conn Info    "host=ec2-107-22-255-345.compute-1.amazonaws.com 
                 port=5432 dbname=dk2sf5va7dsalklkdsj3rd 
                 user=uy5gymvzvyast6ee sslmode=require 
                 password=pssajjhjhfa2yzx1q8g48dp1mo3a"
    
  • VS1: Verification step 1: Note down the count of users in the current database

    $ heroku console
    >> User.count
    => 1024
    >> exit
    
  • Enable the mainenance mode. This will prevent any further changes to the shared database.

    $ heroku maintenance:on 
    
  • Create a backup of the shared database. Note down the backup id.

    $ heroku pgbackups:capture --expire 
    
    SHARED_DATABASE (DATABASE_URL)  ----backup--->  b136
    ?[0KCapturing... doneB -
    ?[0KStoring... done
    
  • VS2: Verification step 2: Check the count of users in the dedicated database. The database will throw an error in this step.

    $ psql "host=ec2-107-22-255-345.compute-1.amazonaws.com port=5432 dbname=dk2sf5va7dsalklkdsj3rd user=uy5gymvzvyast6ee sslmode=require password=pssajjhjhfa2yzx1q8g48dp1mo3a"
    => select count(*) from users; 
    ERROR:  relation "users" does not exist
    LINE 1: select count(*) from users;  
    => \q
    
  • Seed the dedicated database from the the backup

    $ heroku pgbackups:restore HEROKU_POSTGRESQL_RED b136 --confirm
    
    ?[0KRetrieving... donet |
    ?[0KRestoring... doneB \-
    
  • VS3: Verification step 3: Count of users in the dedicated database should match the count returned in the step VS1

    $ psql "host=ec2-107-22-255-345.compute-1.amazonaws.com port=5432 dbname=dk2sf5va7dsalklkdsj3rd user=uy5gymvzvyast6ee sslmode=require password=pssajjhjhfa2yzx1q8g48dp1mo3a"
    => select count(*) from users; 
     count
    -------
      1024
    (1 row)
    => \q
    
  • Make the dedicated database as the primary database for your application

    heroku pg:promote HEROKU_POSTGRESQL_RED
    
  • VS4: Verification step 4: Count of users in the heroku console should match the count returned in step VS1

    $ heroku console 
    >> User.count
    => 1024
    >> exit
    
  • Activate the application

    heroku maintenance:off --account thinkspeed
    
  • Deactivate the paid shared database plan

November 16, 2011
Setting up a custom sub-domain for the staging environment on Heroku

Let us say you have configured a custom domain; http://www.foobar.com; for the production environment of your application on Heroku. You followed the instructions here to create a staging environment. Now, you want to expose the staging environment on http://staging.foobar.com. I had a similar problem today, and I didn’t find any step by step instructions for addressing the problem.

Pre-requisites

  • Production and staging Heroku environments are called foobar-production and foobar-staging. Both environments have custom_domains add-on
  • The foobar-production environment has the Zerigo add-on. The A(foobar.com) and CNAME(www.foobar.com) records are configured using Zerigo add-on

Add the staging sub domain to point to the staging environment

    $ heroku domains:add staging.foobar.com --app foobar-staging 

Configure the Zerigo add-on to point to the staging environment.

Clone the CNAME record for www.foobar.com. The record points to proxy.heroku.com. Change the sub-domain name to staging. Wait for 10 minutes for the changes to propagate. Access the staging environment using http://staging.foobar.com.

November 1, 2011
Accessing a property in a nested hash

While accessing a property in a nested hash we need to handle two boundary conditions:

  1. Missing ancestor for a property

    confg = { :log => {:level => "warn"} }
    confg[:log][:level] # returns "warn"
    confg[:email][:host] # exception, missing ancestor email.
    
  2. Missing property

    confg[:log][:file]  # returns nil
    

There are many ways to handle this, but the one I like most is this:

class Hash
  def nested_fetch key, options={}
    key.to_s.split(".").reduce(self, &:fetch) 
  rescue KeyError, IndexError => ex
    options[:default]
  end
end

Now the hash can be accessed as:

confg.nested_fetch("log.level")   # returns "warn"
confg.nested_fetch("email.port")  # returns nil
confg.nested_fetch("email.host", :default => "3000")  # returns 3000

October 19, 2011
Accessing nested attributes from an ActiveRecord object

Let us say we have the following models in our project:

class User < ActiveRecord::Base
  has_one :profile
  attr_accessible :name
end

class Profile < ActiveRecord::Base
  belongs_to :user
  belongs_to :company  
  attr_accessible :location
end

class Company < ActiveRecord::Base
  has_many :profiles
  attr_accessible :name
end

In our view, we are trying to display user name, user location and user company name using the code below:

<% @users.each do |user %>
  <tr>
    <td><%= @user.name %></td>
    <td><%= @user.profile.location %></td>
    <td><%= @user.profile.company.name %></td>
  <tr>
<% end %>

We can DRY the code if we add a nested accessor to ActiveRecord class.

# user.read_nested("profile.location")
# user.read_nested("profile.company.name")

class ActiveRecord::Base
  def read_nested(attrs)
    attrs.split(".").reduce(self, &:send)
  end
end

Now the view code can be rewritten as follows:

<% @users.each do |user| %>
  <tr>
    <% %w(name profile.location profile.company.name).each do |key| %>
      <td><%= @user.read_nested(key)%></td>
    <% end %>
  <tr>
<% end %>

June 22, 2011
Code has consequences: When did the Rails community decide Taiwan is a Province of China?

Recently, we needed a country select field for a form. We decided to use the official country select plugin from the rails team. While testing the new UI, one of the team members noticed Taiwan was listed as:

Taiwan, Province of China

I was quite intrigued and decided to dig deeper to find out how rails community agreed for the transfer. The land grant can be found in the following line:

"Taiwan, Province of China", "Tajikistan", ....",

Why does Rails team call Taiwan a province of China?

As usual, there is always a simpler explanation for most of the conspiracy theories. It looks like the rails team took the official country names published by ISO.

Why does ISO call Taiwan a province of China?

Here is the official explanation given by ISO:

The names in ISO 3166-1 - and thus on our Webpage - are taken from United Nations sources. These sources are authoritative inputs to the international country code standard. They are:

  • The United Nations Bulletin Country Names
  • Country and Region Codes for Statistical Use of the United Nations Statistics Division

Since Taiwan is not a UN member it does not figure in the UN bulletin on country names. The printed edition of the publication Country and region codes for statistical use gives the name we use in ISO 3166-1. By adhering to UN sources the ISO 3166/MA stays politically neutral.

According to ISO it’s being politically neutral by following UN.

Why does UN call Taiwan a province of China?

This probably is a topic for a long form article for some journalist.

Code has consequences


This political dispute was fought via UN documents, media, text books and by influencing a foreign government to accept/reject Taiwan’s statehood. Until now, rest of the world didn’t have to take sides in this dispute. But now, rest of the world is unwittingly taking sides as more and more sites on the internet are using ISO-3166 as the source for the country names.

I favor the suggestion made by Dan Jacobson in this thread on Debian message board. We (i.e. rest of the world) shouldn’t have to take sides, we shouldn’t have to choose between ‘Republic of China’ OR ‘Taiwan, Province of China’. We should simply call Taiwan as it’s commonly known, i.e. Taiwan.

Bottom line: Code has consequences.

References:

2:17pm  |   URL: http://tmblr.co/ZTlFMx6L7825
(View comments
Filed under: rails China Taiwan 
June 18, 2011
Fix for Paperclip error; NotIdentifiedByImageMagickError; on Windows 7(64bit)

I use the paperclip gem for attachment management. Recently, I installed ImageMagick to a location suggested by the installer on my laptop(running Windows 7-64bit).

C:\Program Files\ImageMagick-6.7.0-Q16

I set the command_path to a long file name in config\initializers\paperclip.rb.

Paperclip.options[:command_path] = 'C:\Program Files\ImageMagick-6.7.0-Q16'

When I tried to upload an image, the server threw an error.

[paperclip] An error was received while processing: 
  #<Paperclip::NotIdentifiedByImageMagickError: C:/.../Temp/xx.JPG 
  is not recognized by the 'identify' command.>

After some debugging I found a bug in the Paperclip gem in lib/paperclip/command_line.rb file.

def full_path(binary)
  [self.class.path, binary].compact.join("/")
end

The full_path function generates a long file name with a backslash.

"C:\Program Files\ImageMagick-6.7.0-Q16"/identify

This command fails on Windows as the cmd shell throws an error when the long file contains a back slash.

There are two ways to fix the issue.

Use the short file name as the command path.

Paperclip.options[:command_path] = 'C:/PROGRA~1/IMAGEM~1.0-Q'

Note: You can get the short file name as follows:

dir /x "C:\Program Files*"
dir /x "C:\Program Files\ImageMagick-6.7.0-Q16*"

Monkey patch the Paperclip gem in config\initializers\paperclip.rb.

class Paperclip::CommandLine
  def full_path(binary)
    [self.class.path, binary].compact.join((File::ALT_SEPARATOR||File::SEPARATOR))
  end
end if defined?(Paperclip::CommandLine)

Now, the identify command is generated with the correct path seperator.

"C:\Program Files\ImageMagick-6.7.0-Q16"\identify

I prefer the second approach as command_path is easier to configure.

Note I tested the patch on Paperclip 2.3.11

June 15, 2011
Running the rails debugger on Windows 7(64bit)

I recently got a new a new laptop. After installing Netbeans(6.9.1) on the machine, I tried to run the debugger as usual. Netbeans waited for around 10 seconds and refused to start the debugger. It took me a while to notice the brief error message in the status bar:

Could not connect to the web server... cannot show http://localhost:3000

After turning the IDE logging ON, I found the following exception in the IDE log file:

C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `gem_original_require': no such file to load -- require_relative (LoadError)
from C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `require'
from C:/r/lib/ruby/gems/1.8/gems/linecache-0.45/lib/linecache.rb:66
from C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `gem_original_require'
from C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `require'
from C:/r/lib/ruby/gems/1.8/gems/ruby-debug-base-0.10.4/lib/ruby-debug-base.rb:3
from C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `gem_original_require'
from C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `require'
from C:/r/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.17.beta5/lib/ruby-debug-ide.rb:5
from C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `gem_original_require'
from C:/r/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29:in `require'
from C:/r/lib/ruby/gems/1.8/gems/ruby-debug-ide-0.4.17.beta5/bin/rdebug-ide:7
from -e:1:in `load'
from -e:1

I had following software/gems on my machine:

Windows 7 (64bit)
Ruby 1.8.7
Rails 2.3.9
ruby-debug-ide (0.4.9)
ruby-debug-base (0.10.4 mswin32)
linecache (0.45)

The issue was due to the latest version of linecache gem. I had to revert to an older version(0.43) to get around the issue.

I did the following to fix the issue:

gem uninstall ruby-debug-ide ruby-debug-base linecache
gem install ruby-debug-ide

Re-install ruby-debug-base gem

gem uninstall ruby-debug-base
gem install  ruby-debug-base --platform mswin32

Re-install linecache gem

gem uninstall linecache
gem install  linecache  -v 0.43

June 15, 2011
Migrating to SASS 3

Today, I migrated to the latest version of the compass gem. Which required the latest version of the sass gem. The new sass gem broke my sass files as they were in sass 2 format. I had the following gems installed on my machine:

compass (0.11.3)
sass (3.1.2)
haml (3.1.2)

After spending some time on Google I came across this article on sass2 to sass3 conversion. I ran the sass-convert tool.

$sass-convert --from sass2 --to sass --in-place --recursive .

But, I got the following error:

Unknown format for sass-convert --from: sass2
Use --trace for backtrace.

I asked a question about this issue on the compass forum. It turns out the sass-convert tool honored the sass2 input format in sass 3.0 gem. The latest version does not support sass2. I did the following to get the conversion working:

$ gem uninstall haml sass
$ gem install  sass --version "~> 3.0"
$ sass-convert --from sass2 --to sass --in-place --recursive .
$ gem uninstall haml sass
$ gem install  sass

Liked posts on Tumblr: More liked posts »