RudyGems

Matthew Rudy Jacobs
see me swim
Github
see some of my code
Thought Sauce
Hire me in Hong Kong

Configuring foreman for Production and Development

I follow the convention;

  • Procfile defines all processes
  • .foreman set specific foreman variables

Development:

  • .env sets environment variables for each developer
  • .env.example sets defaults for development
  • foreman start starts all processes

Production:

  • heroku config sets environment variables
  • heroku ps:scale turns on or off whichever processes are needed for production

Here’s an example from a project.

Procfile:

web: bundle exec unicorn_rails -p $PORT -c ./config/unicorn.rb
worker: bundle exec rake jobs:work
search: bundle exec rake sunspot:solr:run

.env.example:

# default S3 bucket
S3_KEY=keykeykeykeykeykey
S3_SECRET=secretsecretsecret
S3_BUCKET=myapp-development

.env

# developer's private S3 bucket
S3_KEY=mememememememememe
S3_SECRET=mysecretmysecret
S3_BUCKET=myapp-development

.foreman:

# development port is 3000
port: 3000

The daily `bundle update`

A typical process for me is like this.

I start off with

  • a dependency on Rails 3.1.10
  • a dependency on any version of koala

So my Gemfile says exactly this

gem "rails", "3.1.10" gem "koala"

Every day I do a bundle update. Sometimes there are new versions of gems, sometimes there aren’t.

One day there is a new version of koala released koala (1.6.0)

When I do my daily bundle update everything breaks. It turns out that koala (1.6.0) relies uponfaraday (0.8).

For some reason this breaks my app.

So I realise I have a new dependency, and I add it to my Gemfile.

gem "rails", "3.1.10" gem "faraday", "0.7" # 0.8 breaks for some reason

Dealing with these problems in small doses, on a daily basis, makes it easier to deal with.

cd -Tmp-

How do I cd to a directory starting with a hypen (-)?

# /var/folders/*whatever*/ has a folder named '-Tmp-'
$ ls
-Caches-/ -Tmp-/ 

# lets try and CD there
$ cd -Tmp-
-bash: cd: -T: invalid option
cd: usage: cd [-L|-P] [dir]

# or maybe make sure its a directory
$ cd -Tmp-/
-bash: cd: -T: invalid option
cd: usage: cd [-L|-P] [dir]

# try and escape the first -
$ cd \-Tmp-
-bash: cd: -T: invalid option
cd: usage: cd [-L|-P] [dir]

# quote it
$ cd '-Tmp-'
-bash: cd: -T: invalid option
cd: usage: cd [-L|-P] [dir]

# double quote it
$ cd "-Tmp-"
-bash: cd: -T: invalid option
cd: usage: cd [-L|-P] [dir]

# escape it in the quotes
$ cd '\-Tmp-'
-bash: cd: \-Tmp-: No such file or directory

# escape it in the double quotes
$ cd "\-Tmp-"
-bash: cd: \-Tmp-: No such file or directory

# try a "./" hack
$ cd ./-Tmp-/

$ echo "WHOOP"
WHOOP

(Source: gist.github.com)

Fed up of `bundle exec rake`? Control your `rage`!

For the past year we’ve all been happy.

rake was stable at 0.8.7

You could run

rake

In any project and it’d just work.

But now, with the release of rake 0.9.0, sometimes we get this

RudiMac:3rdhome matthew$ rake
rake aborted!
You have already activated rake 0.9.0,
but your Gemfile requires rake 0.8.7.
Consider using bundle exec.

(See full trace by running task with --trace)

And there’s a simple solution.

RAGE!

#!/usr/bin/env bash
if [ -f Gemfile ]; then
  bundle exec rake $@
else
  rake $@
fi

Either copy and paste the gist into an executable (~/bin/rage maybe)

Or follow these instructions;

git clone git://gist.github.com/1003927.git ~/rage-gist
mkdir ~/bin
cp ~/rage-gist/rage ~/bin/
chmod a+x ~/bin/rage

As long as ~/bin is in your path you should be set.

rage db:migrate test --trace

BOOM!

I forgot to commit to a feature branch!

So I just committed to master

commit b17a1fbe8f5d59c24a1f2bb50c9905f8345263f5a
Author: Jeffrey Giraffe <Jeffrey.T.Giraffe@gmail.com>
Date:   Wed May 18 18:22:22 2011 +0800
  Started work on an exciting new feature.

But I shouldn’t have.

All features should be in a “feature branch”

How do I move my commit onto a different branch?

Luckily I haven’t pushed yet.

So just start my “feature branch” right now.

git checkout -b exciting-new-feature
git push origin exciting-new-feature

Then go back to master, and undo the commit

git checkout master
git reset --hard HEAD~1

Or if there are 3 commits

git reset --hard HEAD~3

Of course, if I’ve already pushed this would be a little more tricky.

I suggest (for verbosity) you shouldn’t try to do anything fancy.

Just revert it

git revert HEAD

and humbly explain why

Revert "Started work on an exciting new feature."

This commit is not ready to be on master yet,
and has been moved onto the branch "exciting-new-feature"

This reverts commit b17a1fbe8f5d59c24a1f2bb50c9905f8345263f5a.

Boom!

Running a Test Case only when we have internet

So I have some tests for geocoding, that I want to be run live.

test "geocoding" do
  record = Address.create!(:address => "Pretty Cottage, Winding Road, Beautiful Country")
  assert_equal 51.59011, record.latitude
  assert_equal -2.995398, record.longitude
end

Of course, these will fail when there’s no internet.

My choices;

  • mock the geocoding API
  • let them fail
  • only run this test when there’s internet

I chose the latter.

How do I know I have internet connection?

Can I ping google?

system "ping -q -c 1 -t 1 google.com 1> /dev/null" #=> true / false

Complication!

the above works on OSX (where -t1 sets a timeout of 1 second)

but on Linux -t has a different meaning, and -w1 sets the timeout

Compromise: ignore timeouts for the moment

system "ping -q -c 1 google.com 1> /dev/null" #=> true / false

Stick this in a method

def requires_internet!
  if can_ping_google?
    yield
  else
    flunk "this test needs to be run when there is internet"
  end
end

Now incorporate this into our test.

test "geocoding" do
  requires_internet! do
    record = Address.create!(:address => "Pretty Cottage, Winding Road, Beautiful Country")
    assert_equal 50.0, record.latitude
    assert_equal -0.3, record.longitude
  end
end

Done.

Here’s the gist. Fork it and make it better!

I broke RubyGems.org

Yes that’s right.

I broke RubyGems.org.

No April Fools Joke! (although this did happen after midnight HKT)

… I’ve hidden the cause so they have a chance to fix it…

… but its a unicode thing …

I packaged it with gem-this, and did a `gem push` it turned out http://rubygems.org was down!

I went to bed hoping it would go away, and woke up on April 1st morning to find an email;

Hi Matthew! Looks like you just found a bug that made our homepage unhappy.

=> #<Rubygem id: 39928, name: …,

I straight up deleted that gem. Can you send or paste the gem/gemspec
with that so we can make sure this doesn’t happen again?

-Nick

So, there you go!

Rubygems.org currently can’t support unicode gem names!

Upgrading Postgres 8.4 to 9.0 with Homebrew

I hoped it’d be as simple as a `brew install postgresql`

And it almost was.

But…

RudiMac:merlot matthew$ tail -f /usr/local/var/postgres/server.log
FATAL:  database files are incompatible with server
DETAIL:  The data directory was initialized by PostgreSQL version 8.4, which is not compatible with this version 9.0.3.

How do I fix the data files?

Turns out there is a `pg_update` method to do this for you.

But it requires a bit of manual work.

# First of all stop the server
launchctl unload -w ~/Library/LaunchAgents/org.postgresql.postgres.plist

# backup the old data directory
mv /usr/local/var/postgres /usr/local/var/postgres.old

# now create a fresh postgres 9 data directory
initdb /usr/local/var/postgres

Now we’re ready to do the upgrade.

pg_upgrade -d /usr/local/var/postgres.844/ -D /usr/local/var/postgres -b /usr/local/Cellar/postgresql/8.4.4/bin -B /usr/local/Cellar/postgresql/9.0.3/bin
...
Upgrade complete
----------------

Boom Ting

Now just add the launch control back in and we’re off.

cp /usr/local/Cellar/postgresql/9.0.3/org.postgresql.postgres.plist ~/Library/LaunchAgents
launchctl load -w ~/Library/LaunchAgents/org.postgresql.postgres.plist
Hong Kong Ruby Group Christmas Photo

Hong Kong Ruby Group Christmas Photo

Javascript parseInt() may not do what you expect!

I was shocked today to find I’d introduced a bug.

It manifested itself like this;

This might seem ok.

Except the “Number of repayments” is set by javascript as;

the number of days interest

less the number of days before repayment begins

Looking at the dates, the “number of days before repayment begins” should be 2.

But the difference is -6.

Something is wrong.

And the answer is here;

var date_from_field = function(field_id) {
  var field = $(“#”+field_id);
  var year, month, day;

  var date_bits = field.val().split(“-“);
  var year  = parseInt(date_bits[0]);
  var month = parseInt(date_bits[1]);
  var day = parseInt(date_bits[2]);
 
  return new Date(year,month-1,day);
};

I take a date field

<input type=”date” value=”2010-12-08” />

I grab the value

"2010-12-08"

I split it into year, month, and day

[“2010”, “12”, “08”]

I turn them into integers

[2010, 12, 0]

Then I make them into a date

new Date(2010,11,0); // Tue Nov 30 2010

No problem!

Except…

"2010-12-08" != Tue Nov 30 2010

The problem is

parseInt(“08”) == 0

parseInt(“08”, 10) == 8

"08" is 0 in octal

Always use parseInt(something, 10)