Mark Gandolfo's Blog

Node.Js Knockout Retrospective & Dns Bot App

Posted on August 28, 2010

It was a crazy 48 hours! My team members @coenhyde and @nathanhoad and myself had little knowledge of node.js and really didn't know how to even start a project. But we investigated a bunch of frameworks and decided on:

ExpressJS as our main framework.
Jade as our template language (which was integrated into express)
Less for our stylesheets
MongoDB for our database server

It all started with a mad rush to understand what the hell was happening within node, and more importantly how we could implement our idea! The event based architecture that node is built around made for an interesting adventure since our whole team is mainly PHP and Ruby on Rails developers.

The first day was spent finding our feet, given the massive amount of nodeJs plugins and frameworks, but by the end of the day we had a good idea of the scope of the technology and more importantly a good idea of how much code we could cut within the remaining 24 hours.

We decided to ditch our original idea and move more towards a simple tool that every technologist has been craving! We called it DNS Bot App and its primary purpose is to assist you in the propagation of a domain.

It works by pinging a variety of root servers all around the globe and building a picture of where your domain is resolving. for this first iteration it will show you A records, but stay tuned for more to come!

All in all, Node Knockout was in my opinion a complete success, the goal of the competition was to get a few more people involved in Node and more importantly build some buzz around it. Personally my goals going into the competition was simply to learn a new language, and although I'm nowhere near an expert, I really feel I've crossed that first hurdle that exists when learning a new language!

So if you think that DNS Bot App may be useful for you now or in the future, please show some support and Vote for us!

So a big shoutout to the node.js team, node knockout crew and of course my team members. It was a cool beer filled and sleep deprived ride, but one I'm looking forward to doing again!


Word Countr

Posted on August 27, 2010

I just wrote a simple rails app to count words in a block of text!

You can find it at http://wordcountr.com/. I built it mainly to play around with rails3 but also I hated the fact there wasn't an easy way to count words in a document.

So I've created this. I hope to implement some Natural Language Processing in the future to give more details about the block of text a user submits!


Rails3 With Cucumber, Rspec

Posted on August 22, 2010

Initially I had a few problems getting rspec and cucumber (especially gherkin) working with rails3 beta and ruby 1.9.2! Mainly these problems I ran into seemed to deal with bundler.

So easy enough, to get cucumber and rspec working, add the following to your Gemfile

group :test do
  gem 'webrat'
  gem 'rspec'
  gem 'capybara'
  gem 'database_cleaner'
  gem 'cucumber-rails'
  gem 'cucumber'
  gem 'rspec-rails'
  gem 'spork'
  gem 'launchy'
end

then run

bundle install

chances are the first time you try to run your tests (especially if you're using rvm) you'll have segfaults displayed. To fix this manually remove the natively compiled gets and reinstall them using the gem command.

i.e.

gem uninstall gherkin nokogiri 
gem install gherkin -v=2.1.5
gem install nokogiri -v=1.4.3.1

Do this for each of your segfaulting gems and things should start to work!


Mysql Gem With Rails 3 And Ruby 1.9.2

Posted on August 21, 2010

The traditional mysql gem that was used with ruby 1.8.7 and rails 2.* no longer works with rails3. The new mysql gem for rails 3 and ruby 1.9.2 is now called ruby-mysql, it takes the same params as the original mysql gem so to install it on a mac, try something like

env ARCHFLAGS="-arch i386" gem install ruby-mysql -- --with-mysql-dir=/usr/local/mysql --with-mysql-lib=/usr/local/mysql/lib --with-mysql-include=/usr/local/mysql/include

and add the following line in your Gemfile

gem 'ruby-mysql'

Hudson Ci Server Running Selenium/Webdriver Cucumber In Headless Mode Xvfb

Posted on July 01, 2010

I was determined to get our CI server running cucumber features in headless mode. I ran into a few webdriver problems which resulting in a small monkey patch (capybara patch being written and submitted) for capybara.

This is how I got it running on a fedora 12 server (and some tips on getting it working on an ubuntu server).

Install Xvfb

On fedora

  sudo yum install xorg-x11-server-Xvfb

on ubuntu

  sudo apt-get install xvfb

Running Xvfb

To run Xvfb, in console simply type, then set a environment variable to bind all X requests from the command line to go to the new virtual deskspace

  Xvfb -ac :99
  export DISPLAY=:99

This will launch a new virtual display bound to display 99.

Install X11VNC to see whats happening!!

This is very cool. You can actually set up a vnc server and bind it to the virtual display to see what is happening!!!

On Fedora

  sudo yum install x11vnc

On ubuntu

  sudo apt-get install x11vnc

To run

Simple run the following command! And point your VNC client to the installation server!

x11vnc -display :99

Test it by going to the command line and typing something like xterm or firefox!

Hudson

Install the hudson gem

The hudson gem is in the gems repo, but for docmentation go http://github.com/cowboyd/hudson.rb. I generally do this as the user "hudson".

  gem install term-ansicolor
  gem install yajl-ruby
  gem install httparty -v=0.5.2
  gem install builder -v=2.1.2
  gem install thor -v=0.13.6
  gem install hpricot 
  gem install hudson --pre

Install hudson

On the command line just type

  hudson server 

this will install hudson, and save configuration to the ~/.hudson directory

Checkout your application to this box

First thing is to ensure you have set up a git user and email in the global config

  git config --global user.name "hudson"
  git config --global user.email "hudson@myserver.com"

Then clone your app down, install all associated gems and create your testing database

  git clone git@github.com:username/mygitrepo.git
  rake gems:install
  rake db:create:all
  RAILS_ENV=test rake db:schema:load

Test cucumber/webdriver runs

Type cucumber in your apps directory

Create a new Hudson Project

Thanks to the hudson gem, you can set up the inital project skeleton via the command line (isn't technology great) Here we can use the hudson create command and tell hudson to use the current directory, and that hudson is installed on localhost:3001

  cd #{to_your_rails_app}
  hudson create . --host localhost --port 3001

Set up the hudson project

Log into the project, if its on your local computer, point your browser to http://localhost:3001 and click on your project, also skip this next section.

If you're installing hudson on a remote server you'll need to ssh port forward since hudson at this point is only listening on localhost.

  ssh -L 8123:localhost:3001 hudson@mytestserver.com

Then open a browser and point it to http://localhost:8123 and click on your project

Set up the build

  1. Remove all defined build sets.
  2. Add a new build step "Execute Shell" with the command "cp config/database.tests.yml config/database.yml"
  3. Add a new build step "Exceute Shell" with the command "RAILS_ENV=test rake gems:install"
  4. Add a new build step "Execute Shell" with the command "RAILS_ENV=test rake db:migrate"
  5. Add a new build step "Execute shell" with the command "spec spec" # if you have specs
  6. Add a new build step "Execute shell" with the command "DISPLAY=:99 cucumber" # with cucumber

Press the save button.

If webdriver doesn't append to your virtual display

If webdriver doesn't append to your Xvfb then you can put this script in /features/support/capybara_webdriver_patch.rb

# Added profile support for capybara, so we can run our tests in headless mode
class Capybara::Driver::Selenium < Capybara::Driver::Base
  def self.driver
    unless @driver
      profile = Selenium::WebDriver::Firefox::Profile.new
      profile.load_no_focus_lib = false
      @driver = Selenium::WebDriver.for :firefox, :profile => profile
      at_exit do
        @driver.quit
      end
    end
    @driver
  end
end

Some after thoughts

Some extras you should set up before you think your finished. They're outside of the scope of this document but there are plenty of docs out there on the interwebs who can give you all the information you need to rock and roll.

  • At the moment its open to everyone, go to global configuration and set up ACL's
  • Your builds aren't very continuous yet, you can schedule builds periodically by going into the project configuration area, or I believe you can tie it into githubs callback mechanisms

Observers In Rails

Posted on June 21, 2010

In an effort to reduce the clutter of before and after callbacks in your Rails models an Observer can be used. In a simple use case, you may want to give the user 500 credits in your online store when they signup.

Without an observer your User model would look something similar to

class User < ActiveRecord::Base
   def before_create
     self.credits = 500
  end
end

Which is fine, if thats all that is in your model. But once your model starts to grow its generally a good idea to keep the callbacks in a different location! Observers to the rescue! With a Rails Observer your code would look similar to

# models/user.rb
class User < ActiveRecord::Base
end

# models/user_observer.rb
class UserObserver < ActiveRecord::Observer
   def before_create(user)
     user.credits = 500
  end
end

Now tell Rails that you want your observer to be included

# config/environment.rb 
Rails::Initializer.run do |config|
  config.active_record.observers = :user_observer
end

Rails will automatically understand that this observer is for the user class based on the name (convention over configuration to the rescue). Although you can also have an observer where the model can't be inferred by the name, in this case you can explicitly define the models the observer should be observing.

For instance, lets say we have an Audit observer, for a number of models.

  class AuditObserver < ActiveRecord::Observer
    observe :user, :item

    def after_update(record)
      AuditTrail.new(record, "UPDATED")
    end
  end

This will observe the user model and on an observed update will create a new audit trail record. Sexy huh?

So no excuses, clean your code up, use observers! Its a sexy design pattern which I feel is completely underused!


How To Debug Rails Apps

Posted on June 20, 2010

Coming from PHP I used to rely heavily on the die() command to print out debugging information. In rails nobody could really tell me if there was an equivalent, I was told to "raise", which I'm sure everyone feels is a bit dirty to use.

So I thought I'd quickly put up a few ways I debug in Rails.

Ruby-Debug

Its a sexy little gem that lets you easily step through your code and even drop into an IRB session. To use it, make sure you have the gem or plugin installed and then.

require 'ruby-debug'; debugger

Ruby debug shines when running a script/server (mongrel, webrick, etc) but can also be used with passenger, but with limitations.

Abort

This is equivelent to the PHP die() command. It takes an argument, evals and prints the statement to the screen. Note that it does halt execution.

abort('hello world')

This is a nice hacky way to print something out to the screen very fast, no matter where you are in your application.

Debug

Debug lets you easily eval something to a screen in your views.

debug('hello world')

Now that you have a bunch of debugging commands with rails, please stop using raise() to debug!


Send Keys Released!

Posted on June 09, 2010

Send keys is a capybara extension that lets you send keystrokes to an element in the browser. It uses webdriver so must be used using the @javascript tag in your features.

Check it out at http://github.com/markgandolfo/send-keys and read about it at http://markgandolfo.com/pages/send-keys

How to use it

First make sure you use the @javascript tag, to force capybara to use the webdriver driver.

Then in your features you can send characters or modifier keys to an element, or an array of modifier keys and keys. You'll need to use the css selectors to select an element.

For Example

    # Send the 'a' character to the input who's id is search (#search)
    And I send a to "input#search"
    
    # Send the 'a', 'b' and 'c' characters to the input who's id is search (#search)
    And I send abc to "input#search"
    
    # You can put them in quotes if you feel more comfortable
    And I send 'abc' to "input#search"
    
    # You can also send modifier/special key strokes to an element
    And I send arrow_left to "input#search"
    
    # You can even send a combination of modifier and characters
    # This will result in a the charcater 'A' being sent to the input
    And I send [shift, a] to "input#search"
    
    # Or maybe you just want to press enter
    And I send enter to "input#search"

    # How cool would it be to test the counter in a text area (say for a twitter app)
    And I send hello to "#message"
    And I should see "135" in "characters_left"
    And I send backspace to "#message"
    And I should see "135" in "characters_left"
    
    # We used it to test completion suggestions
    # The first suggested name was highlighted and responded to an enter keypress
    And I send "bo" to "input#username"
    And I should see "bob" within "username_suggestions"
    And I send enter to "input#username"

Curl From Within Text Mate

Posted on May 07, 2010

I have created a small command for textmate that lets you curl a file from within textmate.

The source is on github

Installation

git clone git://github.com/markgandolfo/tmbundle.curl.git

Navigate to the download directory and double click on the curl.tmbundle file

How to use

^ ⌥ ⌘W will pop a dialog box up, place the url in text field and press enter.

The file will download and your project drawer (or project+ drawer) will refresh!

Possible Todo

  • Add progress bar for larger files
  • Possibly download to the current open file path (maybe add a checkbox or something)
  • Maybe add some sort of output if the url can't download for some reason (404, 500, etc.)

Sqlite3 Uninitialized Constant Encoding

Posted on April 17, 2010

I was getting a crazy error while trying to migrate/create a sqlite3 database using rails 2.3.5 today. After trolling the interwebs, and the source code I finally found a hint in the stack trace that sqlite3 gem was being called half way through the filter chain.

So to fix.

gem uninstall sqlite3

And make sure you only use

gem install sqlite3-ruby

Happy hacking!


Git Completion On A Mac

Posted on April 05, 2010

To enable bash for git you need to include the git bash completion script in your profile

cd GIT_SRC/contrib/completion
cp git-completion.bash ~/bin
echo "source ~/bin/git-completion.bash" >> ~/.profile
. ~/.profile

Or simply enough if you have the latest git version from macports, follow this one command to automagically include the bash completion file in your profile shell script

echo "source /opt/local/var/macports/software/git-core/1.6.5.3_0+doc/opt/local/share/doc/git-core/contrib/completion/bash_completion.bash" >> ~/.profile

And then reload your profile

. ~/.profile

And hey presto!


How To Alias A Class Method In Ruby

Posted on March 30, 2010

To alias a class method, you can't just use the alias/alias_method methods.

Lets say we have a simple System Event class that has a log() method.

class SystemEvent
  def self.log
    // Do things in here (maybe database / file log depending on log levels)
  end
end

If for some reason we would want to alias log to be log_me, Then I would have to lay out my class as follows

class SystemEvent
  def self.log
    // Do things in here (maybe database / file log depending on log levels)
  end
  
  class << self 
    alias :log_me :log
  end
end

Changing The Cookie Domain Path In Rails

Posted on March 24, 2010

In rails 2.3.4+ if you want to modify your cooking information set by your system, in any of your environment files you can simple overwrite them as follows.

config.action_controller.session = {
:session_key => '_my_session_id',
:secret => '..your_secret_code_here..',
:domain => ".domain.com"
}

Obviously if you only want to change your domain for instance you can simple do

config.action_controller.session[:domain] = ".domain.com"

Git Tips

Posted on March 16, 2010

I'll just post a few quick little command line git commands.

Basic Commands

Sync the meta data (e.g. branch names, tag names, etc) with remote.. This will not update the branches, just the names, etc.

git fetch

To see a list of remote branches

git branch -r

To see a list of local branches

git branch

# or

git branch -l

To see both local and remote

git branch -a

Branching

To create a new branch from the branch you are currently on.

git checkout -b new_branch

To delete a branch

git branch -d new_branch

To delete a remote branch

git push origin :new_branch

To checkout into a new branch, and merge uncommitted changes

git checkout -mb new_branch

To checkout into an existing branch, merging uncommitted changes

git checkout -m existing_branch

Checkout a remote branch (one that you haven't checked out before)

git checkout --track -b branch_name origin/branch_name

Tags

To tag at the current point in time on the current branch

git tag new_tag

To push tag to a remote

git push --tags

To delete a tag (locally)

git tag -d new_tag

To delete a tag from a remote

git push origin :tags/new_tag

Rails Plugin: Associated With?

Posted on January 16, 2010

I've just released a new plugin called associated_with, that allows you to check if two objects are associated.

Check out the write up: http://markgandolfo.com/pages/associated-with

Or the GitHub Repo: http://github.com/markgandolfo/associated_with