Friday, October 12, 2007

How to setup mac ox for Facebook call back URL

1. Type ifconfig en0 in the terminal. The output will be like:

en0: flags=8863 mtu 1500
inet6 fe80::211:24ff:fed6:3436%en0 prefixlen 64 scopeid 0x4
inet AAA.XXX.Z.YYY netmask 0xffffff00 broadcast 192.168.1.255
ether 00:11:24:d6:34:36
media: autoselect (1000baseT ) status: active


2. Go to Linksys, Applications and Gaming tab, Port Range Forwarding and give a name for the application, specify start and end port (ex 3000 &B 3010), Protocol is both, To IP Address will have AAA.XXX.Z.YYY value, check the enabled box. Click on Save Settings.

3. In setup, DDNS tab, select DynDNS.org as the DDNS service and provide the username, password and hostname that you specified when you created an account with DynDNS.com site. System value is Capture(ddn.dynamic)Dynamic. All other values are default. Click Update and Save Settings.

4. Login to Facebook and specify the hostname and values for other parameters consistent with the above steps.

That's it. Now you can run the Facebook app and it will call your Rails app running on your machine.

Thursday, October 11, 2007

Tuesday, October 09, 2007

RSpec Not Implemented Feature

In the regular test unit, I do something like:

def test_load_upcoming_events_for_the_week
puts "Not Implemented : test_load_upcoming_events_for_the_week"
assert true
end

def test_load_top_4_categories
puts "Not Implemented : test_load_top_4_categories"
assert true
end

All my to do items goes into the autotest output and I have easy access to my to do list.

Integrating Flash With Rails

1. Install flashobject helper rails plugin
script/plugin install http://lipsiasoft.googlecode.com/svn/trunk/flashobject_helper

2. Include <%= javascript_include_tag :defaults %>

3. In the view: <%= flashobject_tag "/flash/demo.swf %>

Monday, October 08, 2007

Using Capistrano 1.4.1 when you already have 2.0

1. sudo gem install daemons gem_plugin mongrel mongrel_cluster --include-dependencies
2. sudo gem install capistrano -v 1.4.1
3. cap _1.4.1_ long_deploy

Sunday, October 07, 2007

Sake Headaches on Rails 2.0 Preview release

1. sudo gem install ruby2ruby -y
2. sudo gem install sake
3. sake -i bootstrap.rake

throws the error:

/usr/local/lib/ruby/gems/1.8/gems/sake-1.0.11/lib/sake.rb:315:in `parse': /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:2028:in `const_missing': uninitialized constant Sake::TasksFile::RAILS_ROOT (NameError)

RESTful authentication with Rails 2.0

1. script/generate authenticated user --include-activation creates Rails 1.2.3 style migration.

So, I changed it to:

class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users, :force => true do |t|
t.string :login, :email, :remember_token
t.string :crypted_password, :limit => 40
t.string :salt, :limit => 40
t.string :activation_code, :limit => 40

t.datetime :remember_token_expires_at, :activated_at
t.timestamps
end
end

def self.down
drop_table "users"
end
end

2. The routes.rb looks like:

ActionController::Routing::Routes.draw do |map|
map.resources :users
map.resource :session

map.connect '', :controller => 'home', :action => 'index'

map.with_options :controller => "users" do |page|
page.signup "/signup", :action => "new"
page.activate "/activate/:activation_code", :action => "activate"
end

# Install the default routes as the lowest priority.
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end

I had to define named route for signup because if I use new_user method in the application.rhtml, I kept getting error.

I don't know how to define the route in a RESTful way for activation. So I have named route for it.

3. In the form:

<% form_for @user do |f| -%>

<% end -%>

That's it. I am able to signup and activate using Rails 2.0. Of course I had to rename the .rhtml files to .html.erb. Now the Textmate shortcuts are broken, since it recogizes only rhtml files.

Thursday, October 04, 2007

Avoid Heavy Response Processing in Rails

I am half-way through the Topfunky's Peepcode Code Review pdf book. It is very well written.

In my previous job, I had to find a way of processing records that was created by users and send them to an external vendor. My pointy haired boss told me to spawn a thread for this purpose. I suggested using some kind of messaging system for obvious reasons. In the end we compromised and settled for Rake task and cron job combination.

Peepcode's book talks about this issue in detail.

Tuesday, October 02, 2007

uninitialized constant Rails::Initializer::MemCache

1. sudo port install memcached
2. sudo gem install memcache-client

That got rid of the error message.

Friday, September 28, 2007

Intridea

I am excited to join forces with my friends in DC and work on some kick-ass Rails projects. Intridea has grown very fast in less than a year. Almost 15 Rails developers now.

I just ordered 30 inch Mac Cinema Display. I will be working from home, which will be fun and much more productive than going to an office. Finally no distractions and stupid meetings!!!

swf chart vs gruff

Need to evaluate them when I get some time. Requested Geoff to produce a screencast on Selenium on Rails. He responded back after a few days saying he has to learn it and has included it in this todo list.

Ruby Idioms Presentation

Here is the link to the presentation. Thanks to Pelle for his review on his website.

Thursday, September 20, 2007

How to use Will Paginate 2.0 Rails plugin

Step 1: In the controller:
@users = User.paginate(:order => 'created_at DESC'
:conditions => ["active = ?", 1]
:per_page => 10,
:page => params[:page])

Step 2: In the view:
<%= will_paginate @users, :inner_window => 10, :outer_window => 10 %>

This will create page links from 1 to 10 then dots followed by numbered links for last 10 pages.

Step 3: To make the pagination links sexy, copy the following CSS (Digg style):

div.pagination {
padding: 3px;
margin: 3px;
}

div.pagination a {
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #AAAADD;

text-decoration: none; /* no underline */
color: #000099;
}
div.pagination a:hover, div.pagination a:active {
border: 1px solid #000099;

color: #000;
}
div.pagination span.current {
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #000099;

font-weight: bold;
background-color: #000099;
color: #FFF;
}
div.pagination span.disabled {
padding: 2px 5px 2px 5px;
margin: 2px;
border: 1px solid #EEE;

color: #DDD;
}

Reference: Err the blog.

Tuesday, September 18, 2007

San Francisco Ruby Meetup

I presented my Ruby Idioms today at the San Francisco Ruby Meetup. It was my first presentation and I was very excited. It was full of examples and practical tips. Some of the idioms were described in the context of Rails applications. Soon I will be posting the link to the actual presentation in pdf format. Enjoy!

Tuesday, August 28, 2007

Rails Performance Notes

Static Caching

- Cache on demand through Rails
- Cron sweeper (minute.rb?)
- JS + cookie for username
- Caching functional test
- ngnix config (run it locally for testing?)
- deploying cron job


Performance

1. Query optimization - query analysis (doing n queries instead of joins)
2. Rails static page caching
3. Asset packager - Firebug Net tab (Page lead times, "apparent" performance)
4. Number of optimal Mongrels ( Topfunky screencast )
5. Rails log - Page load times, Query times
6. Unix diagnostics
- Top
- Vmstat
- MySQL tools
- tail / grep etc
7. Periodic reporting
8. Benchmarks

Friday, August 17, 2007

PostgreSQL on Mac OS

MySQL suddenly stopped working and I was not able to run it. I got frustrated with MySQL error messages like no /tmp/mysql.sock found and -bash: /usr/local/mysql/bin/mysql: Bad CPU type in executable

22:04:59:/usr/local/src > mkdir postgres
22:05:24:/usr/local/src > cd postgres/
22:05:27:/usr/local/src/postgres > ls -l
22:05:29:/usr/local/src/postgres > curl -O ftp://ftp5.us.postgresql.org/pub/PostgreSQL/source/v8.2.4/postgresql-8.2.4.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 14.8M 100 14.8M 0 0 48521 0 0:05:21 0:05:21 --:--:-- 77126
22:12:19:/usr/local/src/postgres > tar -xzvf postgresql-8.2.4.tar.gz
postgresql-8.2.4

22:31:26:/usr/local/src/postgres > cd postgresql-8.2.4
22:31:30:/usr/local/src/postgres/postgresql-8.2.4 > ./configure --with-includes=/sw/include/ --with-libraries=/sw/lib
checking build system type... powerpc-apple-darwin8.10.0

22:33:12:/usr/local/src/postgres/postgresql-8.2.4 > make
22:41:07:/usr/local/src/postgres/postgresql-8.2.4 > sudo make install
23:25:46:/usr/local/src/postgres/postgresql-8.2.4 > /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the -A option the
next time you run initdb.

Success. You can now start the database server using:

/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
or
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start

23:29:07:/usr/local/src/postgres/postgresql-8.2.4 > /usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
LOG: database system was shut down at 2007-08-16 23:26:25 PDT
LOG: checkpoint record is at 0/42BEB8
LOG: redo record is at 0/42BEB8; undo record is at 0/0; shutdown TRUE
LOG: next transaction ID: 0/593; next OID: 10820
LOG: next MultiXactId: 1; next MultiXactOffset: 0
LOG: database system is ready

23:35:06:~ > /usr/local/pgsql/bin/createdb
CREATE DATABASE
23:35:33:~ > /usr/local/pgsql/bin/createdb mytestdb
CREATE DATABASE
23:35:45:~ > /usr/local/pgsql/bin/psql mytestdb
Welcome to psql 8.2.4, the PostgreSQL interactive terminal.

Type: \copyright for distribution terms
\h for help with SQL commands
\? for help with psql commands
\g or terminate with semicolon to execute query
\q to quit

mytestdb=# create table foo(name varchar primary key, foo_id serial);
NOTICE: CREATE TABLE will create implicit sequence "foo_foo_id_seq" for serial column "foo.foo_id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
CREATE TABLE
mytestdb=# insert into foo(name) values ('Liz');
INSERT 0 1
mytestdb=# insert into foo(name) values ('Bunny');
INSERT 0 1
mytestdb=# select * from foo;
name | foo_id
-------+--------
Liz | 1
Bunny | 2
(2 rows)

Sunday, August 12, 2007

Acts as Billable Installation

1. script/plugin install http://source.collectiveidea.com/public/acts_as
_billable/trunk/

2. script/plugin install http://activemerchant.googlecode.com/svn/trunk/
active_merchant

3. sudo gem install --source http://dist.leetsoft.com money

4. script/plugin install http://source.collectiveidea.com/public/rails/p
lugins/acts_as_money

Monday, July 30, 2007

How to add Rails plugin files to SVN during install

use -x flag. Example:

script/plugin install -x http://svn.techno-weenie.net/projects/plugi
ns/restful_authentication/

Tuesday, July 24, 2007

Recurring Billing in Rails

Research notes:

Dealing with subscriptions payment
Follow-up to subscriptions
Recharging to the Same Credit Card

Sample test case:

def test_reference_purchase
assert response = @gateway.purchase(Money.new(10000), @creditcard, @options)
assert_equal "Approved", response.message
assert response.success?
assert response.test?
assert_not_nil pn_ref = response.authorization

# now another purchase, by reference
assert response = @gateway.purchase(Money.new(10000), pn_ref)
assert_equal "Approved", response.message
assert response.success?
assert response.test?
end

Acts As Billable Plugin

script/plugin install http://source.collectiveidea.com/public/acts_as_billable/trunk/
There’s a start of a sample app (that uses rspec) that goes with it at http://source.collectiveidea.com/public/acts_as_billable/samples/depot

Authorize.Net Automated Recurring Billing (ARB) Example Code

ARG Guide

Tuesday, July 17, 2007

Help in writing tests in Rails

script/console test

It will load the console in the test environment. Very useful to experiment with the code and write tests.

Saturday, July 14, 2007

Railscookbook example error

NameError in User#list_perms

Showing app/views/user/list_perms.rhtml where line #22 raised:

uninitialized constant UserHelper::Permission

create the permission model without migration.

Also the migration for permissions table does not have a id column. This results in a bug where the update does not work for some cases. So I had to add a primary key column to the permissions table. This fixed the buggy update problem.

How to skip migration in Rails

use --skip-migration switch: Ex: script/generate model user --skip-migration

Thursday, July 05, 2007

How to suppress rendering of layout while generating xml in Rails

def my_xml_method
@foo = Foo.find(:all)
render :layout => false
end

If you have render and respond_to in the same method, you will get the dreaded double render error.

Wednesday, July 04, 2007

How to install RubyInline in Mac OS

$ sudo gem install rubyinline
Successfully installed RubyInline-3.6.3
Installing ri documentation for RubyInline-3.6.3...
Installing RDoc documentation for RubyInline-3.6.3...

Port install did not work:

sudo port install rb-rubyinline
---> Fetching autoconf
---> Attempting to fetch autoconf-2.61.tar.bz2 from http://ftp.gnu.org/gnu/autoconf
---> Verifying checksum(s) for autoconf
---> Extracting autoconf
---> Configuring autoconf
---> Building autoconf with target all
---> Staging autoconf into destroot
---> Installing autoconf 2.61_0
---> Activating autoconf 2.61_0
---> Cleaning autoconf
---> Fetching rb-rubygems
---> Attempting to fetch rubygems-0.9.4.tgz from http://rubyforge.org/frs/download.php/20989/
---> Verifying checksum(s) for rb-rubygems
---> Extracting rb-rubygems
---> Configuring rb-rubygems
Error: Target com.apple.configure returned: configure failure: shell command " cd "/opt/local/var/db/dports/build/_opt_local_var_db_dports_sources_rsync.rsync.darwinports.org_dpupdate_dports_ruby_rb-rubygems/work/rubygems-0.9.4" && /opt/local/bin/ruby -rvendor-specific setup.rb config " returned error 127
Command output: sh: line 1: /opt/local/bin/ruby: No such file or directory

Error: The following dependencies failed to build: rb-hoe rb-rake rb-rubygems rb-rubyforge
Error: Status 1 encountered during processing.

How to use select_tag to create drop down menus in Rails

<%=
select_tag :size, options_for_select(["Small", "Medium", "Large"])
%>

This will create a drop down with the values in the array. You can either declare a constant array in the model and use that like: MyModel::SHIRT_SIZES instead of hard coding it. If it is database driven, write a helper that will return an array of options.

Sunday, July 01, 2007

How to find the helper methods for RESTful nested routes in Rails


1) script/console
2) >> irb ActionController::Routing::Routes
3) rs = ActionController::Routing::Routes
4) rs.named_routes.each {|name, route| puts( name, route) }; 1
5) Just copy the list of helper methods show in the output of step 4 and append path to that name. You must also provide the required ids shown in the output. For example take the output:

user
GET /users/:id/ {:action=>"show", :controller=>"users"}

and in the console, type:

>> user_path 1
=> "/users/1"

The same process can be used for nested routes.

Reference: Rails Routing by David A Black. This book gave me a solid understanding of routes.

Friday, June 29, 2007

Difference between capitalize and humanize in Rails

From the script/console:

>> t = "test"
=> "test"
>> t.capitalize
=> "Test"
>> t.humanize
=> "Test"
>> c = "foo bar"
=> "foo bar"
>> c.humanize
=> "Foo bar"
>> c.capitalize
=> "Foo bar"

How to use hidden field in Rails

<%= f.hidden_field :user_id, :value => current_user.id %>

This passes a hidden variable user_id with the value of current_user.id

Thursday, June 28, 2007

Displaying time only in Rails

Not well documented in the Rails API. Here it is:

<%= f.datetime_select(:time, :discard_day => true, :discard_month => true, :discard_year => true) %>

How to create admin accounts in Rails app

The Memphisto source has rake db:bootstrap task that I use for loading admin users into the database. The dynamic fixture allows using any user and password for a admin account.

Wednesday, June 27, 2007

How to freeze gems using Rake

1. script/plugin install http://svn.ardes.com/rails_plugins/gems
2. rake gems:freeze GEM=gem_name

Monday, June 25, 2007

Migrating Local Subversion Repository to Remote Repository

I have been developing the Rails app on my Powerbook using Subversion with file:/// protocol. So when I had to migrate it to Subversion repository hosted remotely by Rimu I had to do the following:

1) On the laptop:

svnadmin dump ~/home/path/to/svn/repos > some-file-name

2) I used Transmit FTP client to use SFTP to the remote host and copied the some-file-name to the remote machine.

3) Login to the remote machine and run:

svnadmin load subversion-repo-name < some-file-name

I created a new directory on my laptop and did a checkout from remote repository:
svn co --username some_user --password some_password http://www.your-domain.com/project_name/trunk

then svn info shows that the repository is http:// pointing to the remote repository.

svn log http://www.your-domain.com/project_name/trunk

shows all the log messages. Note this did not show all the 10 revisions that I had on my local repository. It showed only the changes that I had made after the migration. So the local repository version was at 10 but the remote repository was moving from version 3.

Debugging Rails App in Realtime with the breakpointer

1) include the line: breakpoint "some description goes here" where you want the program execution to stop.
2) From the rails app root directory run: script/breakpointer
3) Fire the browser and let the app hit the breakpoint, you will be taken to the >> prompt where you can examine variables.

This helped me to customize the Attachment_fu plugin so that image upload is optional.

Saturday, June 23, 2007

Testing XML output in Rails

1. get :action_name, :format => "xml", :id => 1
2. content = @response.body
3. assert_select "title", :text => "Rails Recipes"

The above steps basically simulate http://localhost:3000/xmlcontroller/action_name/1.xml.

Let's say you have multiple records in the xml output you can check:

assert_select "book", :count => 2

In this case there will be two books in xml output.

Thursday, June 21, 2007

.svn: Commit failed

Error:
.svn: Commit failed (details follow):
svn: Out of date: 'vendor/plugins' in transaction '7-1'
svn: Your commit message was left in a temporary file:
svn: '/Users/myprojects/svn-commit.tmp'

svn up first and then svn delete on the files that is no longer required and then commit.

Send Method in Ruby

When you have an object, you can set the values for its attributes by:

obj.send(#{attribute}, value) where attribute is the actual attribute while looping through an array of strings that contains the attribute names. The value is the actual value that is used to initialize the attribute.

Wednesday, June 20, 2007

Recursion in Ruby

Calculate x to the power of y using recursion.

def test(x, y)
if (y == 0)
return 1
else
test(x, y-1) * x
end
end

puts test(2,3)

This was a interesting question during the interview. I never understood recursion. The interviewer skillfully provided some clues for me to figure this one out myself. I wrote down some sample values for x and y in a tabular format. Worked through the problem and surprisingly come up with the right answer!

Tuesday, June 19, 2007

No such file or directory - /tmp/501/nl.uu.phil.SSHAgent.socket (Errno::ENOENT)

I was hacking with passwordless ssh login when Capistrano deployment failed with that message. Running (on Mac OS):

$ ssh-agent bash
$ ssh-add

and then running cap tasks fixed the problem for now.

Monday, June 18, 2007

Using acts_as_reportable Rails plugin to generate CSV data from Active Record

1) sudo gem install ruport -y
2) require "ruport" in environment.rb
3) include acts_as_reportable in your model.

You are now ready to play with the model in the script/console. Very easy and powerful plugin. For more info, check out http://stonecode.svnrepository.com/ruport/trac.cgi/wiki/AARTutorial

Upgraded Ruby to Ruby 1.8.6-p36

This version is compatible with FasterCSV. Hivelogic instructions will work, but you need to use the the url ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p36.tar.gz
to install the latest Ruby distribution. This release was announced on Ruby-Talk mailing list.

You can skip the readline installation if you have it already installed for Ruby 1.8.6 released on march 07.

4 Useful Rails Plugins

PDF Plugin
Calendar Helper Plugin:
Active Record Extensions:
Acts As Reportable

Sunday, June 17, 2007

Pending Deployment Tasks

1) Find out how deploy_with_migrations Capistrano switch works.
2) Change the style.css for the site.
3) How to connect to the database during deployment without using database.yml?
4) How to upgrade if you freeze gems?

This is answered in Rails Recipes. 5) Install Exception Notification plugin and SiteMeter.
6) Contact model, create a secure RSS feed. Refer Rails Recipes.

Deployed Rails App on Staging and Production Environments

1) I looked at the mongrel.log file, the error message said that it
could not find staging.rb. So I created an empty staging.rb file under
config/environments directory.

2) staging configuration for socket value was set to the output of
locate mysql.sock.

3) The staging.log showed that require 'turn' statement in
environment.rb was missing the turn gem. I moved this statement to
development.rb, since it is required only for development.

Missing gem headaches: I also learned about rake freeze gem that allows
taking gems to the deployment environment. But I don't know if I freeze
a gem I will be able to upgrade it later. I will get this clarified from
Rails mailing list.

My emails are being sent, but when I signup I see the link as:

http://localhost.localdomain/activate/7fb260146d37cf5aec957fa0662d94c52a9f2488

http://#{ActionMailer::Base.smtp_settings[:domain]}/activate/#{user.activation_code} line in the rhtml template takes the smtp_settings defined for that environment. So
define the domain in staging.rb to fix this problem

Saturday, June 16, 2007

`No such file or directory – /tmp/mysql.sock`

run `locate mysql.sock` or `locate mysqld.sock` to find where your socket is located, then update database.yml to reflect your system’s configuration. So your entry will be:

socket: /path/to/mysql.sock

Friday, June 15, 2007

Simply Rich Association Plugin Released

I am excited to make my first plugin available for public. You can
checkout the code by doing:

svn checkout http://simply-rich-association.googlecode.com/svn/trunk/
simply-rich-association



Hosted on Google Code: Project home page is http://code.google.com/p/simply-rich-association/

The README file has good explanation of what the plugin can do. http://simply-rich-association.googlecode.com/svn/trunk/README
Enjoy!

Wednesday, June 13, 2007

Komodo IDE 4.1 First Impression

When you run the Komodo it loads all the code intelligence for PHP, Python etc. Very annoying when you want to just work on Ruby. After installation the tutorial instructions tell you to load a certain file. Uhh? Where did it install? It does not know where it installed so you have to manually search to load the tutorial.

There is no way to customize the appearance, no themes. No thanks, I will stick with Textmate for now. Maybe Netbeans might be a good alternative one day.

How to convert a name of a class to Class in Ruby

"Foo".constantize will return Foo. Now you can call any methods on Foo.

Attachment_fu - How to display the image

Mike clark's weblog has a good article on how to use attachment_fu to upload images. In my application I did not need any thumbnails. In this case to display the image in the show.rhtml I had to use the image_tag(@person.public_filename) to display the image.

Adding multiple files to Subversion at once

svn st | grep "^?" | awk '{ print $2}' | while read f; do svn add $f; done

If you want all the ? files to be added. Found this tip here http://www.gregwhitescarver.com/blog/2006/05/22/add-multiple-files-in-subversion-at-once/

Creating admin accounts using Rake task

Memphisto project by Rick Olson has a Rake task called db:bootstrap that is in bootstrap.rake file. It creates admin accounts from the data specified in the users.yml file. Awesome!!!

How to export data from one database and import into another.

mysqldump -u root -p myapp_staging some_table > mytable.sql

and then

mysql -u root -p myapp_acceptance < mytable.sql

Rails Refactoring to Resources - Using CRUD and REST in Your Rails Application

Nice book from Apress written by Trotter Cashion. I finished reading this book last night. It has a very good coverage of the RESTful goodness in Rails. Short and sweet. Learned a lot from this book. Very well written. I give it 4.5 out of 5 stars. The reason is ActiveResource in the latest Rails is not discussed in the book.

Saturday, June 09, 2007

svn: Out of date: '/trunk' in transaction '2-1

When I commit the changes to the svn, I got:
svn ci .
Sending .
svn: Commit failed (details follow):
svn: Out of date: '/trunk' in transaction '2-1'
svn: Your commit message was left in a temporary file:
svn: '/Users/balaparanj/work/zepho/ard/svn-commit.tmp'

Out of date here means the repository version is not the same as the local version. It works after doing svn up.

Tuesday, May 15, 2007

Rails Performance Screencast notes

Here is the notes I took notes from topfunky's httperf screencast.

Production Log Analyzer is a gem that lets you find out which pages on
your site are dragging you down.

Change one thing at a time and benchmark. Take actual data from
production db, export it and use it for benchmarking. Create a
separate environment for benchmarking.

Install httperf. Need 2 machines one for running httperf client and
the other for running Rails app.

Shut down all unnecessary programs on both machines to reduce CPU
usage. This reduces unpredictable results.

Process for Benchmarking Webapplication using Httperf

1) rake sweep_cache
2) mongrel_rails start -e production (no logging)
3) Hit a particular page once
4) run httperf (with consistent args)

Step 1 and 2 is run on Rails app machine. Go to browser on the client
machine load the page and run:

httperf --server machine_name --port 3000 --ur /page_name --num-conns 1000

The number of connections parameter can be changed. In the output of
the httperf make sure that you get number of replies is same as total
connections. Reply status should not have any errors. If there are any
httperf errors the results must be tossed out.

Copy the "Reply rate" line of the httperf output for different number
of connections and use topfunky's script to generate graphs.

./script/parse_httperf_log log/httperf-sample-log.txt

Tuning Mongrel for Performance

Here are the steps for finding how many requests per second a single
Mongrel process can handle.

httperf --server machine_name --uri /page_name --port 3000 --num-conns
7000 --rate 650 --hog

650 is the requests/sec

If this process hangs for more than 20 secs then we have overloaded
Mongrel. Httperf should have no errors (because it means httperf was
overloaded, in that case data must be tossed out).

Try different values for number of connections and rate, such as 6600,
660, 6700, 670 etc. Till the reply rate reaches a maxium and begins to
drop off.

Scaling Rails - Notes from Silicon Valley Ruby on Rails Meetup

Some websites are launched by getting it on TechCrunch, Digg, Reddit
etc. In such cases there is no time to grow organically.

Resources:

1. The Adventures of Scaling Rails -
http://poocs.net/2006/3/13/the­adventures­of ­scaling­stage­1
2. Stephen Kaes "Performance Rails" - http://railsexpress.de/blog/f
iles/slides/rubyenrails2006.pdf
3. RobotCoop blog and gems -
http://www.robotcoop.com/articles/2006/10/10/the­sof
tware­and­hardware­that­runs­our­sites
4. OReilly's book "High Performance MySQL

This presentation's focus is on what's different from previous
writings. For comprehensive overview refer the above resources.

Scribd.com was in launched in march, 07. It is the "YouTube" for
documents and it handles around 1 Million requests per day.

Current Scribd Architecture

1 Web Server
3 Database Servers
3 Document Conversion Servers
Test and Backup machines
Amazon S3

Server Hardware

Dual, dual core woodcrests at 3 Gz
16 GB of memory
4 15K SCSCI hard drives in a RAID 10
Disk speed is important. Don't skimp; you're not Google, and it's
easier to scale up than out.
Hosted by Softlayer.

Software

CentOS
Apache/Mongrel
Memcached, RobotCoop's memcache-client
Stefan Kaes' SQLSessionStore - This is the best way to store peristent sessions.
Monit, Capistrano
Postfix

They ran tests and found out that fragment caching improved
performance for their web app.

How to Use Fragment Caching

Consider only the most frequently accessed pages.
Look for pieces of the page that don't change on every page view and
are expensive to compute

Just wrap them in a
<% cache('keyname') do %>
...
<% end %>
Do timing test before and afterwards; backtrack
unless significant performance gains

Expiring fragments - 1. Time based

Use memcached for storing fragments
It gives better performance
It is easier to scale to multiple servers
Most importantly: It allows time­based expiration

Use plugin http://agilewebdevelopment.com/plugins/memcache_fragments_with_time_e...
Dead easy:
<% cache 'keyname', :expire => 10.minutes do %>
...
<% end %>

Expiring fragments - 2. Manually

No need to serve stale data
Just use: Cache.delete("fragment:/partials/whatever")
Clear fragments whenever data changes
Again, easier with memcached

They also discussed about how to use 2 database servers with Rails
app. For more information you can see the slides at
http://www.scribd.com/doc/49575/Scaling-Rails-Presentation

Q & A

They use SWF open source plugin for uploading documents (it allows
multiple docs to be uploaded simultaneously)

They pay only $100 monthly for Amazon S3 for 5 tera bytes of b/w
usage. Downside of using Amazon S3 is that they cannot generate
analytics for that part of the app.

The uploaded files goes to a queue and is processed in the background.
So the documents don't appear immediately on the site if the load is
high.

Tip from the first presentation on CacheBoard: It uses backgroun drb
plugin by Ezra for exporting documents in XML format.

Tuesday, May 01, 2007

Configuring Selenium to Run Automated Tests

Had to dig out this buried info on Selenium to get the browser to run the automated tests.

Also the Selenium tests are not independent of each other. The tests within a particular file depend on what page the previous test has ended. Strange but if you don't know this you will end up spending lot of time banging your head against the wall.

Colorizing ZenTest output

To get the green and red color for autotest:

1. sudo gem install --remote Redgreen
2. put the statement: require 'redgreen' in the environment.rb

restart the autotest if is already running. Now you will have green color for passing scenario and red for failing tests. Enjoy!

Monday, April 30, 2007

Tests : Before

21:32:17:~/clients/brep/td/trunk > rake stats
(in /Users/balaparanj/clients/brep/td/trunk)
/Users/balaparanj/clients/brep/td/trunk/config/boot.rb:38:Warning: require_gem is obsolete. Use gem instead.
+----------------------+-------+-------+---------+---------+-----+-------+
| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
+----------------------+-------+-------+---------+---------+-----+-------+
| Controllers | 1158 | 972 | 28 | 118 | 4 | 6 |
| Helpers | 329 | 283 | 0 | 42 | 0 | 4 |
| Models | 975 | 759 | 25 | 127 | 5 | 3 |
| Libraries | 733 | 552 | 9 | 82 | 9 | 4 |
| Components | 0 | 0 | 0 | 0 | 0 | 0 |
| Integration tests | 0 | 0 | 0 | 0 | 0 | 0 |
| Functional tests | 701 | 522 | 52 | 106 | 2 | 2 |
| Unit tests | 493 | 382 | 26 | 62 | 2 | 4 |
+----------------------+-------+-------+---------+---------+-----+-------+
| Total | 4389 | 3470 | 140 | 537 | 3 | 4 |
+----------------------+-------+-------+---------+---------+-----+-------+
Code LOC: 2566 Test LOC: 904 Code to Test Ratio: 1:0.4

ssh: somedomain.org: No address associated with nodename

This error message happened while remote login using ssh. ping command did not work. The problem was the domain was incorrect.

Saturday, April 28, 2007

Ruby: No such file to load -- ubygems (LoadError)

I deleted the contents of directory site_ruby and I was getting that error message. After some googling found Rich Kilmer's reply

"You have installed rubygems and set the RUBYOPT variable. This is the
downside to using the RUBYOPT :-(

Just unset that variable and then you should be good to go."

-rich

Thanks Rich, that fixed my problem.

rmagick headache on mac os

Finally resolved the rmagick installation problems. The actual problem was not rmagick itself but a custom script in my project.

I found the RMagick install script for Mac OS X - Version 0.2.0
on rmagick installation faq.

/opt/local/bin/ruby: bad interpreter:

I was getting the weird ruby bad interpreter error message after I deleted everything under site_ruby directory. I was working on getting the rmagick working on my laptop. I resolved the problem by reinstalling the Ruby 1.8.6 and Rubygems 0.9.2.

Friday, April 27, 2007

warning: multiple values for a block parameter (0 for 1)

In the following irb session the error message indicates that the input parameter is missing.

>> hello = lambda { "hello" }
=> #
>> hello.call
=> "hello"
>> log = lambda { |str| puts "[LOG] #{str}" }
=> #
>> log.call
(irb):16: warning: multiple values for a block parameter (0 for 1)
from (irb):17
[LOG]
=> nil
>> log.call("A test log message")
[LOG] A test log message
=> nil

Friday, April 20, 2007

Capistrano Concepts

Chris Selmer's Capistrano Presentation from the April 5, 2007 DCRUG
meeting is very good.

The Rails Edge conference had discussion on the material
covered in this presentation, but this presentation connected all the
dots for me.

Copying to the clipboard in UNIX

You can send any output to the clipboard by using pbcopy. For example: history | pbcopy will send the output of history command to the clipboard. You can just paste it in email or other document. Very nice. pbpaste will paste the contents of the clip board.

Tuesday, March 20, 2007

How to create drop down boxes in Ruby on Rails

Migration file : 001_create_people.rb

class CreatePeople < ActiveRecord::Migration
def self.up
create_table :people do |t|
t.column :first_name, :string
t.column :last_name, :string
t.column :email, :string
t.column :created_at, :datetime
end
end

def self.down
drop_table :people
end
end

person.rb
class Person < ActiveRecord::Base
has_many :tasks
end

task.rb
class Task < ActiveRecord::Base
belongs_to :user

def self.find_all_person
Person.find(:all, :order => "first_name").map {|u| [u.first_name, u.id] }
end

end

tasks/_form.rhtml

<h2> Create a Task for a Person</h2>
<% form_for ( :task, :url => path, :html => { :method => method } ) do |f| %>
    <p>
    
Title:        <br>
        <%= f.text_field :title, :class => 'text_field' %><br>
    </p>
    <p>
    
Content:
        <br>
        <%= f.text_field :content, :class => 'text_field' %><br>
    </p>

        <br>
        
        <p>Select a priority:
    
          <%= f.select ( :priority, %w { 1 2 3 4 5 6 7 8 9 10 } ) %>
    
        </p>
    </p>

    Person:
            <br>
            <%=
             f.select ( :people_id, @people )
            %>

        </p>
    
    <p>
        <%= submit_tag button_text %>
    </p>

<% end %>

tasks/edit.rhtml
<h1>Editing task</h1>

<%= error_messages_for :task %>

<% form_for ( :task, :url => task_path ( @task ) , :html => { :method => :put } ) do |f| %>
  <p>
    <%= submit_tag "Update" %>
  </p>
<% end %>

<%= link_to 'Show', task_path ( @task ) %> |
<%= link_to 'Back', tasks_path %>

tasks/index.rhtml
<h1>Listing tasks</h1>

<table>
  <tr>
  </tr>
  
<% for task in @tasks %>

<tr>
    <td><%= link_to   ( h task.title ) ,    task_path ( task ) %></td>
  </tr>

<% end %>
</table>

<br />

<%= link_to 'New task', new_task_path %>

tasks/new.rhtml
<h1>New task</h1>

<%= error_messages_for :task %>

<%= render :partial => 'form', :locals => { :path => tasks_path,
                                              :method => :post,
                                              :button_text => 'Create' } %>
                                            

<%= link_to 'Back', tasks_path %>

tasks/show.rhtml

<h2>Task </h2>
    <p> Title: <%=  h @task.title %></p>
    <p>Content: <%= h @task.content %></p>
    <p>Priority: <%= h @task.priority %></p>
    <p>Created At: <%= @task.created_at %></p>
    <p>Person: <%=  @person.first_name %></p> -->
    
<%= link_to 'Back', tasks_path %>

people/_form.rhtml

<% form_for ( :person, :url => path, :html => { :method => method } ) do |f| %>
    <p>
    
    <strong>First Name: </strong>
        <br>
        <%= f.text_field :first_name, :class => 'text_field' %><br>
    </p>
    <p>
    
    <strong>Last Name: </strong>
        <br>
        <%= f.text_field :last_name, :class => 'text_field' %><br>
    </p>

    <strong>Email: </strong>
        <br>
        <%= f.text_field :email, :class => 'text_field' %><br>
    </p>

    <p>
        <%= submit_tag button_text %>
    </p>

<% end %>

people/edit.rhtml
<h1>Editing person</h1>

<%= error_messages_for :person %>

<%= render :partial => 'form', :locals => { :path => person_path ( @person ) ,
                                            :method => :put,
                                            :button_text => 'Update' }
%>


<%= link_to 'Show', person_path ( @person ) %> |
<%= link_to 'Back', people_path %>

people/index.rhtml
<h1>Listing people</h1>
* Create an application to track a person's tasks. The user should be able to
create people, create tasks, and assign a task to a person when the task is created.

<table>
  <tr>
  </tr>
  
<% for person in @people %>
<tr>
    <td><%= link_to   ( h person.first_name ) ,    person_path ( person ) %></td>
  </tr>
  
<% end %>
</table>

<br />

<%= link_to 'New person', new_person_path %>

people/new.rhtml
<h1>New person</h1>

<%= error_messages_for :person %>

<%= render :partial => 'form', :locals => { :path => people_path,
                                              :method => :post,
                                              :button_text => 'Create' } %>


<%= link_to 'Back', people_path %>

people/show.rhtml

<h2>Person </h2>
    <p>First Name: <%=  h @person.first_name %></p>
    <p>Last Name: <%= h @person.last_name %></p>
    <p>Last Name: <%= h @person.email %></p>

<%= link_to 'Edit', edit_person_path ( @person ) %> |
<%= link_to 'Back', people_path %>

home/index.rhtml
<%= link_to  "People",    :controller => :people, :action => :index %><br>
<%= link_to  "Tasks",    :controller => :tasks, :action => :index %>

layouts/people.rhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title>People: <%= controller.action_name %></title>
  <%= stylesheet_link_tag 'scaffold' %>
</head>
<body>

<p style="color: green"><%= flash[:notice] %></p>

<%= yield  %>

</body>
</html>

layouts/tasks.rhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title>Tasks: <%= controller.action_name %></title>
  <%= stylesheet_link_tag 'scaffold' %>
</head>
<body>

<p style="color: green"><%= flash[:notice] %></p>

<%= yield  %>

</body>
</html>

controllers/home_controller.rb
class HomeController < ApplicationController
def index

end
end

people_controller.rb
class PeopleController < ApplicationController
# GET /people
# GET /people.xml
def index
@people = Person.find(:all)

respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @people.to_xml }
end
end

# GET /people/1
# GET /people/1.xml
def show
@person = Person.find(params[:id])

respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @person.to_xml }
end
end

# GET /people/new
def new
@person = Person.new
end

# GET /people/1;edit
def edit
@person = Person.find(params[:id])
end

# POST /people
# POST /people.xml
def create
@person = Person.new(params[:person])

respond_to do |format|
if @person.save
flash[:notice] = 'Person was successfully created.'
format.html { redirect_to person_url(@person) }
format.xml { head :created, :location => person_url(@person) }
else
format.html { render :action => "new" }
format.xml { render :xml => @person.errors.to_xml }
end
end
end

# PUT /people/1
# PUT /people/1.xml
def update
@person = Person.find(params[:id])

respond_to do |format|
if @person.update_attributes(params[:person])
flash[:notice] = 'Person was successfully updated.'
format.html { redirect_to person_url(@person) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @person.errors.to_xml }
end
end
end

# DELETE /people/1
# DELETE /people/1.xml
def destroy
@person = Person.find(params[:id])
@person.destroy

respond_to do |format|
format.html { redirect_to people_url }
format.xml { head :ok }
end
end
end

controllers/tasks_controller.rb
class TasksController < ApplicationController
# GET /tasks
# GET /tasks.xml
def index
@tasks = Task.find(:all)

respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @tasks.to_xml }
end
end

# GET /tasks/1
# GET /tasks/1.xml
def show
@task = Task.find(params[:id])
@person = Person.find(:first, :conditions => "id = #{@task.people_id}")

respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @task.to_xml }
end
end

# GET /tasks/new
def new
@task = Task.new
@people = Task.find_all_person
end

# GET /tasks/1;edit
def edit
@task = Task.find(params[:id])
end

# POST /tasks
# POST /tasks.xml
def create
@task = Task.new(params[:task])
@person = Person.find(:first, :conditions => "id = #{@task.people_id}")

respond_to do |format|
if @task.save
flash[:notice] = 'Task was successfully created.'
format.html { redirect_to task_url(@task) }
format.xml { head :created, :location => task_url(@task) }
else
format.html { render :action => "new" }
format.xml { render :xml => @task.errors.to_xml }
end
end
end

# PUT /tasks/1
# PUT /tasks/1.xml
def update
@task = Task.find(params[:id])

respond_to do |format|
if @task.update_attributes(params[:task])
flash[:notice] = 'Task was successfully updated.'
format.html { redirect_to task_url(@task) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @task.errors.to_xml }
end
end
end

# DELETE /tasks/1
# DELETE /tasks/1.xml
def destroy
@task = Task.find(params[:id])
@task.destroy

respond_to do |format|
format.html { redirect_to tasks_url }
format.xml { head :ok }
end
end
end

Monday, March 05, 2007

sudo: port: command not found

export PATH=$PATH:/opt/local/bin
export MANPATH=$MANPATH:/opt/local/share/man
export INFOPATH=$INFOPATH:/opt/local/share/info

Included the above lines in .bash_profile (my mac is using bash shell) and voila a nagging problem sudo: port: command not found is gone!!!

sudo port -d selfupdate

ran successfully. Now I was able to install FreeImage by running:
sudo port install freeimage

Thursday, March 01, 2007

LoadError: no such file to load — selenium

LoadError: no such file to load — selenium. This kind of error message can happen if you have installed anything as a gem but you have not specified require "rubygems" as the first statement in your program.

Wednesday, February 28, 2007

LoadError: no such file to load — flexmock

If you get this error, it means you need the statement: require 'rubygems' as the first line in your program.

Monday, February 05, 2007

Subversion 1.4.3 upgrade

Installed the latest version of Subversion. I had the older version 1.3, it looks like it installed successfully. svn --version shows the version as 1.4.3 and the files which were already in svn is still there.

Sunday, February 04, 2007

Spam Prevention using the Obfuscator Widget for Mac OS

This plugin obfuscates your email so that spambots cannot recognize the email that you post on your web page.

Testing... my email is : bparanj@gmail.com

CSS Tweak - Nice Widget for Mac OS to optimize CSS

CSS Tweak! widget is very useful plugin to optimize your CSS files. Just select the file you want to optimize from the Finder, hit F12 and drop it into the widget, select the options and the rest is done by the widget! Very cool.

Code to HTML Mac OS widget test - Download Code2HTML

#!/bin/sh
pid=$ ( ps -o pid, command | grep '\<script/server\>' | awk ' { print $1 } ' )
kill -9 $pid
ruby script/server

Code2HTML is a nifty little plugin that helps to convert the code to html. It solved my problem of posting code to the blog without messing up the characters. It is very quick and easy to convert the code to html.

Tuesday, January 23, 2007

Colorizing Autotest

1. install turn and facets
2. require 'turn' in environment.rb in the Rails project.

Step 2 must be done for each project that needs the colorizing of the autotest window. Another way to do this is shown in one of the topfunky's videos.

Friday, January 19, 2007

The new :& syntax in Ruby

The advantage of the new syntax is that it allows passing in a proc object, which is powerful.

I am surprised how the presenter in the No Fluff Just Stuff thought its main purpose was to make the code concise!

Thursday, December 14, 2006

Functional Testing in Rails that Requires Login

For RESTful authentication, there is a
login_as(user) method in AuthenticatedTestHelper module that sets the
current user
in the session from the user fixtures. This is under the lib directory.

In my functional test, I have:

def test_should_show_billing_profile_for_valid_login
login_as (:aaron)
get :show, :id => :aaron.id
assert_response :success
assert_select "html:root>head>title", "BillingProfiles: show"
end

users.yml looks like this:

quentin:
id: 1
login: quentin
email: quentin@example.com
salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
created_at: <%= 5.days.ago.to_s :db %>
aaron:
id: 2
login: aaron
email: aaron@example.com
salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
created_at: <%= 1.days.ago.to_s :db %>


class BillingProfilesController < ApplicationController

before_filter :login_required

def show
@user = User.find(session[:user], :include => [:billing_profile])
@billing_profile = @user.billing_profile

respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @billing_profile.to_xml }
end
end

The problem was that I was using session[:user_id] in my controller
whereas the RESTful authentication
module is using session[:user] as shown below:

module AuthenticatedTestHelper
# Sets the current user in the session from the user fixtures.
def login_as(user)
@request.session[:user] = user ? users(user).id : nil
end
....

So I changed my controller code to use session[:user] and my tests now
pass! The plugin itself has the API to help you do the functional
testing. Very nice indeed.

Monday, December 04, 2006

Installing Sqlite3 on Mac OS 10.4

1. Install DarwinPorts, download DarwinPorts 1.3.2-archive.tar.gz, unzip it.
2. Copy unzipped folder to some location
3. cd to that location cd darwinports/base and run ./configure
4. make
5. sudo make install
6. Add export PATH=$PATH:/opt/local/bin to ~/.profile
7. Either logout of Mac or do source .profile
8. Run port sync
9. sudo port install rb-sqlite3
10.Run sqlite databasename in a shell. You will go to the sqlite command prompt.

You can now create tables and run sql queries. The advantage of this database is that it speeds up the testing during development. It is very fast.

Rails Cheat Sheets

1. Assert Select CheatSheet
2. Ruby on Rails CheatSheet
3. Textmate Rails CheatSheet
4. Scriptaculous CheatSheet
5. RJS Demystified
6. Form Helpers CheatSheet
7. Active Record Relationships CheatSheet
8. AJAX CheatSheet
9. Ruby on Rails Testing CheatSheet
10. TextMate CheatSheet for Rails Developers

Wednesday, November 29, 2006

Email validation plugin

1.Setup the Rails project in Subversion by following the Subversion Primer for Rails blog post.
2. Ran into problems while installing plugins and after reading the James Adams's plugin book, I found the solution, I had to do:

script/plugin install –o https://svn.greenpeace.org/repositories/rails_plugins/validates_as_email/tags/0.1.4

to install the plugin.

I also looked at the test directory of the plugin and did the same assert in my unit test.

Tuesday, November 21, 2006

Restarting WEBrick using script

#!/bin/sh
pid=$(ps -o pid,command | grep '\' | awk '{print $1}')
kill -9 $pid
ruby script/server

This script restarts the Webrick cleanly (doing CTRL+c does not seem to shutdown the server)

Save it in a file, restart.sh. Do a chmod +x restart.sh and type the command: sh restart.sh to run it.

Thursday, November 09, 2006

Rake Aborted! Migration Headache

If the migration is not working in AWDWR Rails examples. Remember that you must be on Edge Rails to make it work.

The Ruby Way, Ruby in a Nutshell and Rails Plugin Extending Rails Beyond the Core

The Ruby Way and Ruby in a Nutshell books arrived from Amazon today. I will post the review when I get a chance.

I also bought the "short cut" Rails Plugins by Addison Wesley, a 100 page pdf book. This book is a gem. More to come soon...

Ruby Interceptor

Beyond Java book had a good example of Interceptor in Ruby. It is like AOP, but is simpler.

1. Create an alias for the method that you want to intercept.
2. Define a new method with the same name as the old method
3. Delegate the call to the old method and add new code to do whatever you want in this method.

You basically open the class, intercept the calls to that method and add additional functionality to the method.

Tuesday, November 07, 2006

Head Rush AJAX

Very good book. Shows the big picture in a very easy to understand way. The concepts are well explained and brings any novice up to speed quickly. This book helped me to move on to study other materials like RJS Templates by OReilly.

Metaprogramming with Ruby

Ruby is a dynamic language. You can create classes and methods at runtime. This is metaprogramming. You can write code that writes code.

Example: Data format driving the code, CSV file with header at the top.

file: people.txt
----------------
name,age,weight,height
"Smith, John", 35, 175, "5'10"
"Ford, Anne", 49, 142, "5'4"
"Taylor, Burt", 55, 173, "5'10"
"Zubrin, Candace", 23, 133, "5'6"

Requirements:
1. The code must not change when a new attribute is added to the existing file or if we are given a different file with different attribute names.
2. The header values such as name and age must be treated as attribute names.

Create a class with a name derived from the file name. First line of the file must have list of attribute names. Checks that can added are: Check the attribute name is a legal Ruby method name, badly formed and missing data.

Given the file name we can create a class from its contents. So:

class_name = File.basename(file_name,".txt").capitalize # Create the class name
# e.g. "foo.txt" => "Foo"
klass = Object.const_set(class_name,Class.new)

Monday, November 06, 2006

Greasemonkey

Awesome Firefox extension, install the plugin and browse the scripts. I installed a script that blocks all Yahoo ads. No more annoying flashing ads in my email account. There are tons of useful scripts. One of the script I installed compares the price of Amazon books with other online stores.

Also, install the scripts one at a time. Install a script and use your browser for sometime and see if everything is fine. This is important because I installed lot of scripts on my laptop and now one of the script is opening up all the links in a new window!

If you install it one at a time, you can easily find out which script is causing the problem.

Metaprogramming - Write code that generates code

Uses

1. Open-Closed principle - Programs that need to pre-generate data tables
2. Mini-language to handle boilerplate code - Programs that have a lot of boilerplate code that cannot be abstracted into functions
3. Programs using techniques that are overly verbose in the language you are writing them in

The art of metaprogramming, Part 1: Introduction to metaprogramming - Jonathan Bartlett

Excellent article on Metaprogramming with Ruby

Sunday, November 05, 2006

How to load fixtures after tables and indexes are created.

Steve Hammond's Blog had this interesting tip:

Can we tell a migration to load the fixtures after it has created the tables and indexes?

Fixtures.create_fixtures('test/fixtures', %w{archetypes tile_types tiles})

The first argument is the directory where the fixtures can be found and the second is an array of fixtures to be loaded. This will load the fixtures into the environment where the fixture is being run. As usual Rails will figure out YAML vs. csv fixtures for you

Thursday, November 02, 2006

Using the Ruby Development Tools plug-in for Eclipse

This plugin allows debugging, check it out.

Resources - Domain Specific Languages in Ruby

1. Seeing MetaClasses Clearly

2. MetaprogrammingWriterTopia by Bill Katz

3. Domain Languages as Rails Plug-Ins: Steve Hammond

4. Meta Rails - Stuart Halloway

5. Neal Ford - Language Oriented Programming Keynote

Script to Setup Rails in Subversion

The following notes is based on the thread Create a rails project skeleton and import and checkout from svn all at once!

1. Create your repository on the server

2. Put the source code in a file called ‘svnrails’ inside of a directory that’s in $PATH. I have mine in /usr/local/bin (where the svn, rails and ruby binaries like to do their thing)

3. This will work with any kind of svn repository (ie. file:///, svn://, http://)

4. If your repository requires authorization, you will be prompted when necessary.

5. I haven’t built any error handling into this, so use the ol’ “measure twice and cut once” technique when typing this command

6. Type the command without arguments for usage

7. You have the option of not creating the /trunk, etc. directories in the repository; and the default command looks like this:

svnrails myapp svn://myserver

8. As long as you’ve created a repository called myapp on the subversion server, this script will automatically import your project into it. In other words, it defaults the name of the repository to be the same as the name of the app; this can be overriden (sensible defaults and all that).

9. Ignores various files in the repository as per the rails wiki

You can find the code here


Doubt: Does this require any changes for Edge Rails?

Wednesday, November 01, 2006

ZenTest Notes

To use unit_diff, pipe normal tests through it:

$ ruby ./TestZenTest.rb | unit_diff

Auto-test:

pressing Ctrl-c once reruns the tests immediately. Pressing the key combination twice terminates autotest.

$ autotest -help

options:

-v Be verbose.
Prints files that autotest doesn't know how to map to tests.

-rails Force rails mode.
Rails will be automatically detected by the presence of config/environment.rb. Use this if you don't have one.

You may need to run 'rake db:test:prepare' before
starting autotest on a rails project.

-vcs=NAME Version control system to update.
Autotest will automatically update every vcstime
seconds.
Autotest understands Perforce (p4), CVS (cvs) and
Subversion (svn).

-vcstime=N Update source control every N seconds.
Defaults to every five minutes (300 seconds).

ZenTest MyProject.rb TestMyProject.rb > missing.rb

./TestMyProject.rb | unit_diff

autotest

multiruby ./TestMyProject.rb

(and other stuff for Test::Rails)

How to use ZenTest on Rails?

ZenTest Documentation

Resources for Testing Ruby on Rails

1. A Guide to Testing the Rails
2. Test First Programming with Ruby
3. Ruby on Rails Testing Cheat Sheet
4. Testing Rails Apps - Mike Clark
5. Test Your Helpers
6. Testing Rails controllers communicating with external web services
7. Test Driven Designg Using ZenTest
8. A Rails Testing Tutorial
9. How to Use ZenTest with Ruby
10. Autotest Rails
11. Testing Rails Apps
12. Selenium on Rails
13. Running Your Rails App Headless
14. YAML Fixtures
15. Testing RJS Templates
16. RJS Assertions
17. 2005 Rubyconf ZenTest Movies - Ryan Davis
18. ZenTest Blog
19. Test-First development