Double Shot #474

Well, I don't know about you, but clearly some people had busy weekends.

Double Shot #473

Looking forward to the weekend, when I can actually be productive.

Double Shot #472

After a rough start with rubyforge, github, and lighthouse all being down, yesterday saw the release of a batch of software:

  • ConfigToolkit - Extensive and flexible code for reading file-based configuration information in ruby.

  • Programmers: Before you turn 40, get a plan B - As a programmer about to turn 50, I'm a bit leery of the notion that age discrimination in the field is as pervasive as some people say, but this blog post does a reasonable job of laying out the issues.

  • RubyGems 1.3.4 - Another point release.

  • Google Quick Search Box - Looks like Google wants to replace QuickSilver.

  • Wagn 1.0 - Milestone release for this slick-looking wiki. I need to find some time to dig in.

  • RedCloth 4.2.0 - New release with some formatting changes. Check the changelog before you update if you use bulleted or numbered lists.

  • Devver - Run tests in the cloud and get them back faster. Looks interesting.

  • Blocky - Crowdsourced spammer blocking for Twitter.

Finding Visitor Locations in Rails

I've got an application that I work on where the client wants to track which countries they're seeing click-throughs from. They want this in real time and in the application's UI, not in an external package such as Google Analytics. There are various ways to guess at country, but for the purposes of this application, basing it on the IP address and where its range is assigned proves to be good enough.

There are various services that will let you geolocate based on IP just by making an API call. But there's no particular reason to go outside your own application for this; it's pretty trivial to set up in Rails:

1) Download the "Complete (Country) One Table" SQL file from IPInfoDB. This is the raw data necessary to do the lookups. Decompress it and then run the resulting SQL file in your application's database. This will give you an ip_group_country table. There's no need to set up a matching model; we're just going to hit it with raw SQL.

2) In this particular application, we're maintaining an Event model that holds, among other things, the IP address of the request. So the easy answer is to geolocate instances of that model when they're created or updated:

[sourcecode language='ruby']
class Event < ActiveRecord::Base
before_save :get_country_info

def get_country_info
segments = remote_ip.split('.')
ip_atom = ((segments[0].to_i * 256 + segments[1].to_i) * 256 + segments[2].to_i)*256
result = connection.execute("SELECT * FROM `ip_group_country` where `ip_start` <= #{ip_atom} order by ip_start desc limit 1;")
row = result.fetch_row
self.country_code = row[2]
self.country_name = row[3]
end

end
[/sourcecode]

3) There is no #3. That's it!

Double Shot #470

I'm sure something happened in Rails-land yesterday, but I didn't see it, so just one link today. More tomorrow, I expect.

  • Firefox 3.5 Preview - If you haven't been seduced away by Safari, here's the latest Firefox, now nearing release candidate status and plenty stable enough for daily browsing.

Double Shot #469

Yup, Monday again. Keeps happening for some reason.

  • Introducing Trample: A Better Load Sampler - James Golick wants to help you beat up your application.

  • Freelancing: Writing Estimates - Advice for not losing your shirt when bidding a development project.

  • sham_rack - FakeWeb for Rack, sort of: a way to stub out external sites via Rack for testing.

  • CUPS - Huh, browser-based printer management on OS X, just visit http://127.0.0.1:631/printers/ - more unixy goodness.

  • Lynxlet - Lynx on OS X. Useful if you ever need to visit a gopher site, I guess.

Double Shot #467

Back on a reasonably early morning schedule. Hopefully I can catch more than worms.

  • Adobe BrowserLab - Adobe hosted service for cross-browser testing. It didn't work on the test page I threw at it, but maybe you'll have better luck.

  • ClickTale - Serious in-page web analytics. I might have some use for this in the future.

  • Joe - Thor scripts to simplify releasing gems to RubyForge.

  • Auto timeout sessions in Rails - Just like banks and stuff use to turn off your browser session.

  • Security Problem with authenticate_with_http_digest - Yeah, Rails had another security issue. It's hardly the worst one ever. I'm very amused by Hacker News trying to get the mob together with pitchforks for this one. (Full disclosure: I'm partially responsible because I passed on the original documentation to the blog entry without spotting the error. Guess I'd better go shoot myself for that.)

Double Shot #464

June...I hope to have some news in June...for now, I just have a load of email to deal with. Enjoy some links.

Double Shot #463

Bird feeders in this neighborhood attract bunnies.

Double Shot #462

I've got more open hours on my dance card for June than I expected. That makes it the perfect time to hire me. :)

Building Rails with Cerberus and multiruby

I've been poking at various continuous integration software lately. Most recently I gave Cerberus a spin, and I must say, even though the project is a bit immature, I like its approach. My test for CI is generally "can I use it on the Rails source" as I think that provides a level of complexity beyond what I'm likely to need for my own projects. Well, I had to contribute a bit of code to get Cerberus to that point, but it works. I also set up the box so that I can build with different ruby versions, thanks to multiruby. Here's my notes on getting all the ducks in a row, starting with a bare-metal Debian Lenny installation.

Root Tasks



  • log in as root

  • adduser webadmin

  • visudo - set webadmin up with sudo rights


webadmin Tasks



  • log in as webadmin


Prerequisites for Ruby Compiles



  • sudo apt-get install autoconf

  • sudo apt-get install bison

  • sudo apt-get install zlib1g-dev

  • sudo apt-get install libzlib-ruby

  • sudo apt-get install ruby-dev



rubygems install



  • mkdir sources

  • cd sources

  • wget http://rubyforge.org/frs/download.php/56227/rubygems-1.3.3.tgz

  • tar -xvzf rubygems-1.3.3.tgz

  • cd rubygems-1.3.3/

  • sudo ruby setup.rb

  • sudo ln /usr/bin/gem1.8 /usr/bin/gem


fastcgi (we'll need fcgi gem later)



  • cd ~/sources

  • wget http://www.fastcgi.com/dist/fcgi.tar.gz

  • tar -xvzf fcgi-2.4.0.tar.gz

  • cd fcgi-2.4.0/

  • ./configure

  • make

  • sudo make install

  • sudo apt-get install libfcgi-dev


Databases



  • sudo apt-get install mysql-server-5.0 libmysqlclient15-dev

  • sudo apt-get install sqlite sqlite3 libsqlite-dev libsqlite3-dev

  • sudo apt-get install postgresql postgresql-server-dev-8.3

  • sudo su - postgres -c 'createuser -s webadmin'

  • sudo su - postgres -c 'createuser -s rails'


memcached



  • sudo apt-get install memcached

  • sudo /etc/init.d/memcached start


multiruby Install



  • sudo gem install ZenTest

  • sudo multiruby_setup mri:svn:tag:v1_8_6_368

  • sudo multiruby_setup mri:svn:tag:v1_8_7_160

  • sudo multiruby_setup mri:svn:tag:v1_9_1_129

  • sudo multiruby_setup update:rubygems


Gem Installs



  • sudo multiruby -S gem install --no-ri --no-rdoc --development test-unit

  • sudo multiruby -S gem install --no-ri --no-rdoc --development fcgi

  • sudo multiruby -S gem install --no-ri --no-rdoc --development memcache-client

  • sudo multiruby -S gem install --no-ri --no-rdoc --development mocha

  • sudo multiruby -S gem install --no-ri --no-rdoc --development mysql

  • sudo multiruby -S gem install --no-ri --no-rdoc --development pg

  • sudo multiruby -S gem install --no-ri --no-rdoc rack

  • sudo multiruby -S gem install --no-ri --no-rdoc thin

  • sudo multiruby -S gem install --no-ri --no-rdoc --development rake

  • sudo multiruby -S gem install --no-ri --no-rdoc --development sqlite-ruby

  • sudo multiruby -S gem install --no-ri --no-rdoc --development sqlite3-ruby

  • sudo multiruby -S gem install geminstaller

  • sudo multiruby -S gem install SystemTimer

  • sudo multiruby -S gem install json


Note: the italicized installs currently fail on ruby 1.9.1.

git



  • sudo apt-get install git-core


Cerberus



  • sudo gem install cerberus


Note: Currently, you'll need to either pull and build cerberus from my fork or from the ruby_builder branch in the official repo. With the next release after 0.5.0, you should be able to use the gem install method.

Create the Cerberus project and build it



  • cerberus add http://github.com/rails/rails/tree/master APPLICATION_NAME=rails_master_187 SCM=git

  • Edit the file ~/.cerberus/config.yml to include your own notifier information

  • Edit the file ~/.cerberus/config/rails_master_187.yml to put in the custom build info:



---
publisher:
mail:
recipients: you@yourdomain.com
scm:
url: git://github.com/rails/rails.git
type: git
# branch: 2-3-stable
builder:
ruby:
task: ci/ci_build.rb
ruby_path: /home/webadmin/.multiruby/install/v1_8_7_160/bin/
success: Rails build finished sucessfully
failure: Rails build FAILED
brokeness: (\d+) failures, (\d+) errors


  • cerberus build rails_master_187


Build databases for ActiveRecord



Note: Some of this depends on having pulled a copy of Rails to the box; the easiest way is to let Cerberus do a failing build and then create the databases.

  • cd ~/.cerberus/work/rails_master_187/sources/activerecord/

  • mysql -uroot -e 'grant all on *.* to rails@localhost;'

  • mysql -urails -e 'create database activerecord_unittest;'

  • mysql -urails -e 'create database activerecord_unittest2;'

  • rake postgresql:build_databases


Ready to Go



Now you can run cerberus build rails_master_187 to run a single build, or cerberus build rails_master_187 force=TRUE to build even if nothing has changed in the repo, or cerberus buildall to build everything you've defined. Hook it up to cron if you want periodic checks of the repo.

subscribe via RSS