Posts from Andy Delcambre - Home...
Posted by adelcambre 11 days ago

Lots of big changes in my life recently. The biggest news is that I accepted a new position at Engine Yard. My first day was last Monday and this has been a very full and extremely fun week. I am really enjoying the technical side of things but the culture at this company is really what does it for me. I have hung out with or grabbed a beer with Dan Peterson, Yehuda Katz, Leah Silber, Corey Donohoe, Jayson Vantuyl, Ed Muller, Lance Walley, Tom Mornini, Michelle Champlin, Nick French, Ben De Jesus and many more I am sure I am forgetting (21st Amendment will do that to you).
As for my actual job at Engine Yard, I am still ramping up, but I am going to be working on internal applications using Ruby, Merb and Datamapper. I am really excited to be using Merb and Datamapper. It is so amazing to work down hall from the guys that invented these frameworks, a truly invaluable resource.
Finally, it was just announced today that Engine Yard has closed their Series B venture capital funding. This round was for $15 million and led by New Enterprise Associates, Inc. (NEA), with participation from Amazon.com and current investor Benchmark Capital. You can see the press release here for more information.
These are very exciting time for both myself and Engine Yard. I am looking forward to finding a permanent place to live down in the bay area and the coming adventures at Engine Yard.
Posted by adelcambre 56 days ago
If anyone is in Portland for RailsConf/Cabooseconf (or any other reason) and wants somewhere to grab some fantastic local beer, the following is a list of my top picks.
1. The Green Dragon
Lots of fantastic beers on tap, pretty decent food I hear but I have never eaten there.
2. Hopworks Urban Brewery
Serves locally brewed hopworks beer. Have had the beer lots of times, haven’t been out to the actual pub yet but have been meaning to make the trek.
3. Produce Row (no website of their own apparently)
Usually has really good beer on tap and an excellent menu. Good atmosphere as well, across from Tazo so you can often smell them making Tea from the back patio.
4. Baileys Taproom
Twenty taps of fantastic beers (usually including a few burly IPA’s, one Nitro tap, and a couple of barleywines).
Also has an extensive bottle menu and wine I think. No food except Cheese and Chocolate but my favorite place to get a beer in Portland. They also have a blog and are baileystaproom on twitter
5. Amnesia Brewing
Serves their own beer, the Desolation IPA is fantastic. The food selection is rather limited, they just have a grill out front that they throw sausages and a few other things on. I always just get a very tasty braut. They have veggie brauts as well.
6. Lompoc Bars
These guys used to be one of my favorites but I feel like they are rapidly turning into the next McMenamins (Lots of locations, mediocre food, beer not as good as it used to be). Still not bad, I like the original and the 5th quadrant.
7. Bridgeport
The local big brewery in Town. Good beer, good food, fairly upscale setting.
8. Deschutes
Another big brewery located in Bend, OR. Has some good beers and the very new Portland pub is fantastic. The Black Butte Porter is probably Deschutes most famous beer.
9. Pilsner Room
Full Sail brewing is a relatively large brewery in Hood River, OR. Their Portland outpost is the Pilsner Room, on the waterfront. It is the bar attached to McCormicks and Schmicks Harborside restaurant and you can get the full dinner menu in the bar. Many of the specialty beers from Full Sail are brewed right there in the bar.
10. Concordia
An excellent place to grab a beer in Northeast. Haven’t been there myself but I hear the food is really good as well.
Any other favorites that I missed (and yes, McMenamins isn’t on my list, I am not a huge fan, and there is much better beer to be had in Portland- see above).
Update: Two suggestions from Justin Palmer
Life of Riley in the Pearl has good beer selections and good food (Close to Cabooseconf as well).
Laurelwood Brewing has a few Portland Locations and makes their own beer. The Pizza place in the Hollywood District is “Family Friendly” (aka over run with kids) but the one on 23rd is much better from what I have heard.
Posted by adelcambre 105 days ago
A few of us from PLANET ARGON were interviewed for a podcast by Scott Hanselman earlier this week primarily talking about our use of Git and git-svn. Planet Argon is currently in the process of moving from Subversion to git. Most of us are using git-svn internally with our central subversion server for now but we are going to be moving to using Git for our central server soon. In preparing for the podcast I thought a lot about what makes git special. I came up with three major reasons.
Branching and Merging
This is my personal number one favorite feature about git. In subversion branching is very easy. It does a shallow copy and is very fast. But merging things back together is a major pain in the butt. You have to keep track of the revision that you branched from just so you can merge them back together.
In git all you do is create a new branch, work as long or as much as you like, then git merge new_branch to merge the changes back into master. There is no need to keep track of revision numbers and the default git merge strategy tends to only have conflicts where there are two changes to the same file in the same place.
Everybody can have their own repo
With subversion or other centralized tools, there is only one main server for each project. I can check the code out on my computer, but I am still tied to that central server for updates. I need to have commit rights to that server to publish my changes. With git, rather than just checking out the code from your repository I can just clone it to my own repo. I will probably have at least one clone on my development computer. But I can also have a complete clone on a server of my own.
I can then make all the radical changes I want and people can pull from me instead of you to get the new stuff. I can then send you an email requesting you to pull from my repo merging my new changes back into the “main” repository.
This is a feature that github really capitalizes on. The built in fork and pull request features are truly top notch.
Offline Commits
As your clone is a full repository just like any other, you can commit directly to it without the need for any central server. This is probably the feature of distributed version control system’s you have heard of the most. The proverbial commit from an airplane. Although it gets repeated a lot, this is actually a very cool feature, and not just for the offline commit.
This all gives you the ability to make commits you might not otherwise make to a central server so as to not clutter up the revision history with your playing around. You can feel free to try things out, commit them, back up to a previous commit, without the central server ever knowing about it.
Thanks again to Scott Hanselman for this opportunity to chat with him. I really enjoyed doing the interview. I think we talked about some good stuff and I am looking forward to listening to it when it gets posted.
Update: The podcast has been posted. Take a listen .
Also, I just forked rails on github!
git clone git://github.com/rails/rails.git
You can read my other articles about git here:
Posted by adelcambre 134 days ago
This is the second part of a series of articles on Git. This post is primarily going to focus on the git reset command and how to track multiple remote subversion branches.
First, a bit of background on git reset. In my opinion it is one of the cooler git commands that I use regularly, it’s function is a bit odd, there is no equivalent in subversion to compare to. What git reset does at a very high level is move a tag in the git graph that makes up the revision history.
So lets take the following sequence of commands as an example.
git init
touch README
git add README
git commit -a -m "initial import"
git checkout -b new_branch
vi README
git commit -a -m "modified README"
git checkout master
vi README
git commit -a -m "updated README"
touch blah
git add blah
git commit -a -m "added blah"
So we create a git repository, make a commit, branch from the commit. Make a change in the branch, and make two changes back in master. The git directed graph now looks like this:

You can see that there are two branches. Right now we are in the master branch so the current HEAD tag points to the 31281c1 commit. (This is important, git reset moves the current HEAD.)
adelcambre@hiro:/tmp/blah% cat .git/refs/heads/master
31281c194e505bf000f1d67c07b76255ac9370e9
adelcambre@hiro:/tmp/blah% cat .git/refs/heads/new_branch
0b6f5c586c257820f2ce94981f71a860107184ed
So now, lets say we want to make master follow the new_branch branch. (This is a bit contrived, bear with me.) So you use git reset --hard new_branch
adelcambre@hiro:/tmp/blah% git reset --hard new_branch
HEAD is now at 0b6f5c5... modified README
So the current HEAD in the master branch is pointing at the same commit as the new_branch branch. Let’s make a commit in each branch and see what happens.
vi README
git commit -a -m "changed README"
git checkout new_branch
touch new_file
git add new_file
git commit -a -m "added new file"
Which gets us this graph:

So, you basically just moved the master branch to be a branch of the new_branch branch. But what happened to those commits against the old master. Well, they aren’t reachable, so would get garbage collected if you did a repack (more on that in a later edition). But for now, they are still there, just not reachable from a tag. We happen to know the commit-id of the old master branch, but if you didn’t, you could use git lost-found.
adelcambre@hiro:/tmp/blah% git lost-found
[31281c194e505bf000f1d67c07b76255ac9370e9] added blah
So it found the old master branch! Let’s merge our current master back into the new_branch, and move master back to the old master.
git checkout new_branch
git merge master
git checkout master
git reset --hard 31281c1
Which results in the graph looking like:

So you can see that we recovered the unreachable commit, and merged back the changes we made on the master branch while it followed the new_branch.
Now, there are no unreachable commits, git lost-found doesn’t return anything, and we are good to go.
git reset options
There are three main options to use with git reset: --hard, --soft and --mixed. These affect what get’s reset in addition to the HEAD pointer when you reset.
First, --hard resets everything. Your current directory would be exactly as it would if you had been following that branch all along. The working directory and the index are changed to that commit. This is the version that I use most often. This is what we used in the above examples. It just says make the current HEAD and working directory exactly like commit “x”.
Next, the complete opposite,—soft, does not reset the working tree nor the index. It only moves the HEAD pointer. This leaves your current state with any changes different than the commit you are switching to in place in your directory, and “staged” for committing. I use this for only every once in a while, and mostly for correcting a commit message. If you make a commit locally but haven’t pushed the commit to the git server or subversion server, you can reset to the previous commit, and recommit with a good commit message. This would look something like:
touch test
git add test
git commit -m "bad commit"
git reset --soft HEAD^
git commit -m "good commit"
So, because git reset --soft doesn’t reset the index nor the working tree, you can just re-commit without having to add anything.
Finally, --mixed resets the index, but not the working tree. So the changes are all still there, but are “unstaged” and would need to be git add‘ed or git commit -a. I use this sometimes if I committed more than I meant to with git commit -a, I can back out the commit with git reset --mixed, add the things that I want to commit and just commit those.
The place that I really use git reset a fair amount is with remote branches. If I have a branch that I want to track a specific remote subversion branch, I can simply git reset --hard svn_branch_name and then git svn does the right thing. I have seen issues where for some reason the git master branch ended up following a subversion tag rather than trunk. A quick git reset --hard trunk cleaned everything up.
I really started liking this command once I realized what was happening. You really need to be aware of the nature of git’s directed graph to take full advantage of git reset, but once you do, you are really able to exploit git quite a lot further.
This is part of a series on git, other articles in the series are:
- Git SVN
- git rebase
- git log
- git stash
- git merge
- git mergetool
Do you have any git reset success stories? Horror stories? Lost work? Saved work? Let me know in the comments.
Update: Changed the terminology to only refer to the current branch as “HEAD”, per comment from Bob.
Posted by adelcambre 142 days ago
I know, I know, this is blog post number one million about Git and git-svn. This is primarily for my co-workers who are wanting to switch to git for our SVN based projects like I have. (If I get them with git-svn, next we can start hosting with git directly, Muhahaha!)
First, a bit of background. Git was written by Linus Torvalds specifically for use by the linux kernel team. He had very specific ideas about how the version control system should work, and none of the offerings at that time satisfied his needs. Git is designed to be distributed (every clone is a full fledged git repository) and very very fast. It is also designed to be very easy not only to branch, but also to merge.
Disclaimer: This is not intended to be the “correct” way to use git + svn, only the way that I use it. That said, here we go.
First, we assume that you have a subversion repository at http://example.com/svn/my_proj. You will need to create the git repo setup to pull from this repo.
git svn init -s http://example.com/svn/my_proj
This will initialize the git repo for pulling from svn. The -s indicates that you have a “standard” setup for your subversion repository. I.e. trunk/ branches/ and tags/. This command will not yet import anything from subversion.
git svn fetch
This command will fetch all revisions from subversion that you have not yet received. The first time you run this could take quite a while. There are options to only fetch some of the revisions, but I prefer to fetch the whole history the first time. This way blame and log show the whole thing.
Now you will have both the whole revision history for trunk, but also all of the branches on the svn server. You can see all of the branches with
git branch -a
This will show all branches, including the remote branches.
Now that you have the entire subversion history stored locally, it can be useful to repack the repository. Right now, each revision has it’s own file, this command will pack those into bigger “pack” files. This will make the repository smaller, but also with many many fewer files
git repack -d
Next you will want to do some actual work on the repository. It is not recommended to make changes in your master branch, so lets make a branch for the new feature.
git checkout -b new_feature
This will make a new branch (the -b) and switch to it (checkout). Once you have your new branch you make a bunch of changes and add a new file or two. You need to add any new files so git knows to track them. You can do this with:
git add path/to/new_file
Now, once you are happy with this new feature and have it tested. You can commit it to git. This is one place where git diverges from subversion. Files you have changed aren’t automatically staged for committing. So right now if you try to commit, you will commit the file that you added in the above command, but nothing you changed (adding a file stages it). So you have two options at this point, you can manually stage each file you want to commit, you will want to do it this way if you don’t want to commit all the changes you have made. That will look something like
git add path/to/edited_file
git add another/edited/file
git commit -m "commit message"
If you want to commit all of the changes you have made, and you have added all of the new files, you can automatically commit all changes, no need to stage. This is how I normally do things. That looks like:
git commit -a -m "commit message"
The -a tells git to commit all staged and unstaged changes.
So now you have these commits in git but they have not been pushed to subversion yet. You will need to get this commit into master first. You need to checkout the master repo, then merge back with the new feature.
git checkout master
git merge new_feature
It is likely this merge will work without any conflicts, but if not you will need to fix the conflicts then commit.
Once you have the commit back in the master repo, you will need to resync the master branch to the svn repo to make sure you don’t commit conflicts.
git svn rebase
This will rebase the master branch to the subversion trunk. Next, you need to push the commit to subversion.
git svn dcommit
That’s it! That is the basic circle between an initial checkout back to a commit. I will be going through the different git commands in the next few weeks to go over how they work in more detail. Here are the things I am planning on covering:
- git reset
- git rebase
- git log
- git stash
- git merge
- git mergetool
Did I miss anything major? Let me know how you use git with svn in the comments.
Posted by adelcambre 150 days ago
Last Thursday (February 21, 2008), I attended a dinner sponsored by the OTBC. The dinner was a chance for people in the open source community in Portland to meet a delegation of open source advocates from Shimane Prefecture in Japan, specifically Matsue.
Included in the delegation were professors from the university in Matsue, representatives from Hitachi and Sun Microsystems, and members of the open source community in Japan including the former head of the PostgreSQL user’s group in Japan.
The highlight of the dinner was Yukihiro “Matz” Matsumoto, the creator of the Ruby programming language. There were about 50 people in attendance at the dinner, but I was very lucky in that I was able to sit at the same table as Matz.

It was very cool to have such amazing access to Matz at this small dinner. We had a good mix of people and backgrounds at our table. Other than Matz and myself, there was Monty Williams from Gemstone and his wife, Ben Matasar from DabbleDB, Audrey Eschright a local community evangelist and member of PDX.rb, Michael Bunsen another PDX.rb member and creator of Urban Edibles, and Anselm Hook from Meedan.
This group allowed for some interesting discussions, we had Monty and Ben who are both smalltalk guys giving some insight into that side of the current sphere of programming. This included some discussions of Seaside the smalltalk web framework.
I had the chance to ask Matz some questions that I have been curious about for some time. Primarily involving the seeming current major transition period for Ruby where we are going from one interpreter which Matz wrote himself, at least 4 or 5 different virtual machines (old MRI, new MRI[YARV], IronRuby, jRuby, and Rubinius), most of which Matz hasn’t worked on. For the first time since Ruby was started, the mainline virtual machine was primarily not written by Matz. It was very interesting to see how he feels about this transition.
Overall the evening was a ton of fun. Lots of excellent discussions, and some amazing access to the creator my favorite programming language on the planet.
Was anybody else there? What was your experience like? Also, if I forgot anybody who was sitting at our table, please post a comment.
Posted by adelcambre 169 days ago
My git workflow usually involves creating a branch for the feature I am working on (or just a bugfix branch) making commits there until the feature is done, then merging back into my master branch and pushing to our subversion server. I started thinking about the fact that if I could simply keep track of all of the time that I spent in the branch it would be a fairly good approximation of the time spent working on the feature. I did successfully implement this and it works fairly well with a few small exceptions.
First, I am using a post-checkout hook in git which is not implemented until version 1.5.4 which is currently at rc4. Luckily the git-checkout script is just a shell script so it was trivial to backport support for the hook. Second, I am using zsh to implement some of the features, and I am not sure if similar things could be accomplished with bash or tcsh.
This technique has three main parts: recording when you enter and leave a branch, calculating the total time spent in the branch, and a system to automatically switch you out of a branch after a few minutes of inactivity.
First the time logging feature. This is the part that uses the post-checkout hook to function. Basically, every time you do a checkout of a branch, the post-checkout script records a timestamp in a log file for the branch you are entering and the branch you are leaving. After a while you build up a log of timestamps in the file. It looks something like this (I standardised again the ISO8601 date format). The post-checkout script is available here
in 2008-01-25T12:36:36-08:00
out 2008-01-25T12:42:43-08:00
in 2008-01-25T13:20:41-08:00
out 2008-01-25T13:29:57-08:00
in 2008-01-25T15:13:47-08:00
out 2008-01-25T15:15:08-08:00
in 2008-01-25T16:56:03-08:00
out 2008-01-25T16:58:09-08:00
Now that you have this time log of the time you spent in the branch, you can calculate how long the feature took you to implement. I used a commit-msg hook to do this. This adds the amount of time the commit took you directly to the commit message. I created this as a script in /usr/local/bin called git-time so you can also run it manually, (the hook is just a symlink). The script also reset the time log file (with just one entry for the current time). The script is a available here
When you commit it adds the time to the commit message:
commit 7e739f01377806be8b93ef181fc99c54058bcd89
Author: Andy Delcambre
Date: Wed Feb 6 14:17:57 2008 -0800
test commit
This commit took 1.35 hours
The last piece ensures that you don’t simply keep the branch checked out all the time and that you switch back to master when you aren’t actually working in the branch. It uses the zsh feature of having a shell TMOUT (which triggers a SIGALRM after the number of seconds specified elapsed), then trapping the alarm and switching to the master branch if you are in a git repository and not already in the master branch.
Here is what you should add to your .zshrc:
TRAPALRM () {
# Used to do time tracking for git commits
if [[ -d .git ]]; then
if [[ `git branch | grep '*' | awk '{print $2}'` != 'master' ]]; then
git co master
fi
fi
}
export TMOUT=300
It seems to work fairly well, but there are a few issues. First, the time log can get screwed up: you can put your laptop to sleep while still in a branch. This results in having a greatly exagerated time in the commit message. I always check with git log to see if the time estimate is approximately accurate, and just reset and recommit (with a greatly under-exaggerated time). There is also always the extra few minutes of work that get done after doing the actual commit (resolving the todo item, merging and committing to the subversion server, etc) so I usually add a bit. But overall it works fairly well for me. Are the other tools that you use to help you with tracking your time?
Posted by adelcambre 219 days ago
I was chatting with some friends today about Macworld 2008, and we discussed what we were expecting to see. I thought I would put my predictions here for posterity’s sake.
So here we go, in no particular order:
- iPhone SDK
Mentioned, but not released
- No new iPhone hardware mentioned (new hardware with 3g and gps announced at wwdc, released in October)
Correct (no new hardware, software update though)
- No new ipods
Correct
- Refresh to the whole portable line, speed bumps, led backlit displays
Wrong (not yet anyway)
- Ultra portable macbook, 13” screen, 3 lbs, SSD (flash disk drive), led backlit display, no optical drive, base $1600, top of the line $2000
Pretty damn accurate, although way off on the top end price.
- Mac Pro refesh, maybe all new look
Refresh a week before, same look
- Appletv refresh
Correct
What do you think? I am drooling over the ultra portable, really hoping to see that one. Also very curious what the iPhone sdk will be like.
Updated with results, these predictions were made on December 18th
What did I miss?
- iTunes movie rentals
- Time Capsule
Posted by adelcambre 220 days ago
I have recently had to sign up for both a Google and Yahoo! maps api key. There is a world of difference between the two sign up processes. First we have yahoo.

There are eight required form fields. Some of which I don’t even necessarily have an answer for. Product name? Description? I want to just play with some maps!
Then there is the authentication section, apparently connect to the non-authentication web services with the generic option, is maps non-authenticated? Kinda hard to know. And there is another question about access scopes which to the uninitiated seems to be asking the same thing as authentication. Over all very confusing (and I consider myself to be fairly technical).
Now, compare to the Google Maps Api Key form.

We have two fields, and one is a checkbox agreeing to the terms of service. Couldn’t get any simpler.
What is the lesson here? Only ask for as much information as you absolutely need to allow the user to start using your application. If I wasn’t using Yahoo! Maps for a client project, I would have given up and gone back to Google.
Posted by adelcambre 252 days ago
On a recent project here at PLANET ARGON we needed to use ActiveRecord with a master and slave database setup. We started out using ActsAsReadonlyable but quickly ran into some nasty performance issues. After asking around a bit, the code ninjas over at ActiveReload mentioned that they had a plugin for splitting the ActiveRecord reads and writes to separate databases called Masochism
This worked much better than ActsAsReadonlyable from a performance perspective but there was an issue with some of our observers. Specifically observers that had conditionals which were contigent on the update that triggered the observer. Take the following (somewhat contrived) example:
class Beehive < ActiveRecord::Base
has_many :bees
end
class Bee < ActiveRecord::Base
belongs_to :beehive
end
class Bee < ActiveRecord::Observer
def after_destroy(object)
object.beehive.destroy if object.beehive.beehive.empty?
end
end
So, destroy the behive when the last bee in the beehive is destroyed. The problem is that the beehive will only be destroyed if all of the bees have been destroyed but there is a race condition when the last bee is destroyed. The database replication has to push the DELETE down to the slave database before the observer gets run (which basically never happens).
The first solution was to simply wrap the observer in a with_master call (with_master is a method on the connection object in masochism to perform any database queries against the master database). It looked something like this:
class Bee < ActiveRecord::Observer
def after_destroy(object)
Comment.connection.with_master do
object.beehive.destroy if object.beehive.bees.empty?
end
end
end
This solved the problem perfectly, the conditional now happens against the master database and will pass at all the right times. But it is a bit ugly to have the with_master call in the observer, the observer shouldn’t care whether it is using masochism or not. Also, we are only using masochism in production, so this breaks on our development copies (the connection only has the with_master method in production).
So after a bit of thinking, and a bit of hacking, I just added the with_master call to ActiveRecord::Observer itself when the plugin is loaded. Here is the patch I used:
Index: vendor/plugins/masochism/lib/active_reload/connection_proxy.rb
===================================================================
--- vendor/plugins/masochism/lib/active_reload/connection_proxy.rb (revision 2039)
+++ vendor/plugins/masochism/lib/active_reload/connection_proxy.rb (working copy)
@@ -20,6 +20,10 @@
def self.setup_for(master, slave = nil)
slave ||= ActiveRecord::Base
slave.send :include, ActiveRecordConnectionMethods
+ # extend observer to always use the master database
+ # observers only get triggered on writes, so shouldn't be a performance hit
+ # removes a race condition if you are using conditionals in the observer
+ ActiveRecord::Observer.send :include, ActiveReload::ObserverExtensions
ActiveRecord::Base.active_connections[slave.name] = new(master, slave)
end
@@ -60,4 +64,21 @@
connection.with_master { reload_without_master }
end
end
+
+ module ObserverExtensions
+ def self.included(base)
+ base.alias_method_chain :update, :masterdb
+ end
+
+ # Send observed_method(object) if the method exists.
+ def update_with_masterdb(observed_method, object) #:nodoc:
+ if object.class.connection.respond_to?(:with_master)
+ object.class.connection.with_master do
+ update_without_masterdb(observed_method, object)
+ end
+ else
+ update_without_masterdb(observed_method, object)
+ end
+ end
+ end
end
There shouldn’t be much performance hit as observers should only be run during a database write (i.e. hitting the master database) anyway.
I am planning on sending it over to Rick Olson and maybe it will be included in masochism itself soon.
Are you using masochism? Are there other issues with observers? Is there a better way to do this (one thing I thought of is to just run observers in a transaction which masochism runs against the master_db as well)? Let me know in the comments.
Posted by adelcambre 260 days ago
I use RubyURL fairly extensively for linking to long urls. It was written internally here at PLANET ARGON by Chris Griffin and Robby Russell.
The RubyURL bookmarklet is a god send, want to link somewhere that has a long url? Just click the RubyURL this link button and copy the address, the problem that I had is that it didn’t work with google maps, which have extremely long urls and requires many steps to generate a RubyURL. First you click, “link to this page”, copy the text from the little popup, go to rubyurl.com, paste the text and get your RubyURL.
I figured that there must be a way to grab that link from the document itself on the Google Maps site. I whipped out my Javascript book and got it working in short order.
The code looks like
javascript:void(location.host=='maps.google.com'?location.href='http://rubyurl.com/rubyurl/remote?website_url='+encodeURIComponent(document.getElementById('link').href):location.href='http://rubyurl.com/rubyurl/remote?website_url='+encodeURIComponent(location.href))
Which is ugly as it’s a bookmarklet. Drag this to your bookmark bar if you want to start using it: RubyURL this Link
You don’t even need to click the “Link to this page” link on google maps before using it, it grabs it right out of the document. I will try to get this added to the RubyURL site as the official bookmarklet as well.
Are there other sites that don’t work well with the bookmarklet? Let me know in the comments!
Posted by adelcambre 309 days ago
The problem
Here at PLANET ARGON we use Subversion for managing our rails projects. There is often concurrent development from different developers on different aspects of a project. It seems that whenever we are adding a lot of new features, we inevitably end up with multiple migrations with the same number. The developer who is the second to commit ends up having to fix the migrations so they can be checked in.
My basic strategy for resolving the conflict is to rollback to a version before the conflict, move my migrations past all of the new migrations and then migrate up to the newest version. The issue with this system is that if you have multiple migrations with the same number, they won’t run at all, so you can’t revert.
The Solution
Lets assume that you are starting a new project which has a blog component. Another developer creates the post model and checks it in, you start working on a user model and create the migration (and run it). In the meantime, the other developer checks in the tag model with a migration. So what you have now is:
001_create_posts.rb
002_create_tags.rb
002_create_users.rb
The posts and users tables are created in your database, the tags table is not. The tags migration is checked into subversion and users isn’t yet. Basically you want to revert to version 1, change users to version 3 then re-migrate. First, to revert to version 1, you need to perform the down operation of the users migration. This can be done with script/console. You require the migration file, then run the migrate method on the class.
Loading development environment.
>> require 'db/migrate/002_create_users.rb'
=> ["CreateUsers"]
>> CreateUsers.migrate(:down)
== CreateUsers: reverting =====================================================
-- drop_table(:users)
-> 0.0854s
== CreateUsers: reverted (0.0856s) ============================================
=> []
Running the migration directly also doesn’t change the schema info table so you will need to use a bit of sql to update that as well.
UPDATE schema_info SET version = 1
Now simply move the create_users migration to version 3,
mv db/migrate/002_create_users.rb db/migrate/003_create_users.rb
and run rake db:migrate and you should be happy again.
Solutions for Avoiding the Conflicts in the First Place
There are basically three options that I have seen for avoiding migration conflicts.
This looks to be a cool plugin that allows you to define your migrations as “Independent”. You subclass the migrations from ActiveRecord::IndependentMigration rather than the normal ActiveRecord::Migration. What this does is if you have two migrations subclassed from IndependentMigration with the same version number, they will both run. This assumes that any dependent migrations will still be numbered differently. It is already available as a plugin at: svn://caboo.se/plugins/court3nay/independent_migrations
This patch (it isn’t a plugin yet) simply replaces the migration version numbers with timestamps, therefore making it much less likely that there will be conflicts. Rather than storing a version number in the schema info table, it stores which migrations have been run. This seems to be a well thought out solution that could work well. I am interested to see this when it becomes a plugin.
Auto Migrations (aka Drop Dead Gorgeous Migrations)
This plugin from Err does away with migrations entirely and makes use of the much maligned db/schema.rb file. You simply change that file to reflect how you want your database to look and run rake db:auto:migrate. The plugin compares the file and your database and applies changes to update your database. This means you can use normal merging/conflict resolution tools you are already used to for changing schema.rb.
This plugin is really new and doesn’t yet support every possible change you could make, it doesn’t yet support type changes and indexes were recently added. It also has some limitations, if you change the name of a column there is no good way for it to detect that. So you end up dropping the old column and creating the new one.
Are there any other solutions that we might not be aware of now?
Posted by adelcambre 324 days ago

For some time now PLANET ARGON has been providing dedicated hosting service for clients who ask. We really enjoy this work and have decided to advertise it a bit more publicly.
What does this mean?
This means you provide a server and we provide a place to put it, somewhere to plug it in and a fast internet connection.
This is not just a colocation service though.
We also provide many services for your hosting needs. We will load the boxes for you and keep them running and patched. We can also provide support for anything up to multiple virtualized instances on your server with complex deployment layouts which we can help configure and deploy.
If this is something you or your company might be interested, please contact us at contact@planetargon.com, +1 503 445 2457, or +1 877 55 ARGON[toll free]
Posted by adelcambre 342 days ago
At PLANET ARGON we use Basecamp for project tracking. Basecamp offers rss feeds of any new posts either globally or per project which is very handy for keeping track of things. The problem is that the rss feeds use http authentication which many feed readers (especially web based ones) don’t support. As a Google Reader user, I was out of luck.
After suffering through using email as my notification system, I decided to write a quick script to convert parameters to the url into http authentication. I initially considered doing this with cgi, but eventually decided to write a quick mongrel handler for the task. It actually turned out to be a lot easier than I thought it would be.
Here is the code:
require 'rubygems'
require 'mongrel'
require 'net/http'
HOSTNAME='your basecamp url'
class SimpleHandler < Mongrel::HttpHandler
def process(request, response)
params = {}
request.params["QUERY_STRING"].split('&').each do |param|
param = param.split('=')
params[param[0]] = param[1]
end
response.start(200) do |head,out|
head["Content-Type"] = "application/xml"
Net::HTTP.start(HOSTNAME) do |http|
req = Net::HTTP::Get.new(params["url"])
req.basic_auth params["user"], params["password"]
response = http.request(req)
out.write response.body
end
end
end
end
h = Mongrel::HttpServer.new("0.0.0.0", "9898")
h.register("/feed", SimpleHandler.new)
h.run.join
It works really well, just run the script and point your feed reader at:
http://hostname:9898/feed?user=&password=&url=
for a normal global basecamp feed, it would look like:
http://hostname:9898/feed?user=andy.delcambre&password=mypassword&url=/feed/recent_items_rss
Robby has confirmed that this works with open id basecamp logins as well.
This could be easily used with any authenticated rss feed you wanted. My goal was to make it general enough and easy enough for everyone at PLANET ARGON to use.
I had no idea it was so easy to add an http server to your script with mongrel. Zed Shaw is the man.
Posted by adelcambre 396 days ago
We had an issue where the nfs server on linux didn’t play nice with solaris client because the solaris clients will try nfsv4 first then fall back to nfsv3. The problem is that by default most linux nfs servers do both v3 and v4 so it answers the v4 request witha failure, so the solaris clients never fall back. Unfortunately it isn’t well documented how to disable v4.
The basic solution is to pass—no-nfs-version 4 to rpc.nfsd when it starts. The normal place to add this is /etc/default/nfs-kernel-server, but there is no NFSDARGS variable in there. A quick look in the init script shows that the contents of $RPCNFSDCOUNT are passed directly to rpc.nfsd.
start-stop-daemon --start --oknodo --quiet \
--nicelevel $RPCNFSDPRIORITY \
--exec $PREFIX/sbin/rpc.nfsd -- $RPCNFSDCOUNT
So it was simply a case of tacking—no-nfs-version 4 onto RPCNFSDCOUNT in /etc/default/nfs-kernel-server giving me:
# Number of servers to start up
RPCNFSDCOUNT='8 --no-nfs-version 4'
(Eight is the default number of servers)
I hope this helps if you need to do the same.
Posted by adelcambre 406 days ago
Rails cookies are weird. In the controller you interact with them like they are a hash, but in fact it is not nearly that simple. The rdocs gives some hints to the fact that weird things are going on but it wasn’t enough for me to figure it out. The hash abstraction works pretty well when you are setting the cookies, but when trying to test them things become more complicated.
Lets take this simple example of setting an auth_token cookie.
cookies[ :auth_token ] = { :value => user.token , :expires => user.expires }
This might happen in the login method of an authentication controller. So now you want to test that the cookie is actually getting set. So you think, ok this is a hash, I can just do something like:
cookies[ :auth_token ].should_not be_nil
This in fact doesn’t work but, (and here is the nasty part), there is still a cookies object defined. What happens as far as I can tell (and correct me if I am wrong) is that once the post request is made, the cookies object is gone. Then you can access the cookies that were set using the response object. But the response.cookies object isn’t the same as the cookies object you were dealing with earlier. It is the cookies as they are seen from the browser. Therefore it is no longer a ruby hash, but an array of values, and the expiration time no longer exists (that is internal to the browser). It is also no longer keyed by symbols, but is now keyed by strings. So the correct way to spec that cookies are set looks like:
response.cookies[ "auth_token" ].should_not be_nil
But, because of the cookies alias alias in the ActionController test suite, you can also use the response.cookies object as just cookies.
Hopefully this will save you the hour I just spent beating my head against this.
Posted by adelcambre 416 days ago
Started work at Planet Argon today. I have been chatting with them for about 6 weeks, and I am extremely excited to start working with them. Today was pretty slow to start (as I expected), getting accounts going, getting mysql working properly on my laptop, getting subversion checkouts, etc, etc. Then I got started working on some actual coding.
I am starting out writing some specs for the project I am working on. I have used rspec for a few different projects but I hadn’t had a chance to play with the new syntax yet. It is basically exactly the same as when I used it just with different method names, but it really makes a huge difference in the style it forces you into.
With the old method, how to describe the specs was always a bit weird to me. For example:
context "a new group with no users" do
specify "group should not be valid" do
#...
end
end
With the new style everything seems to flow naturally. For example:
describe Group, " with no users" do
it "should not be valid" do
@group.should_not be_valid
end
end
Interesting is that I often feel like I write the same thing twice, once in english, then again in the DSL of rspec. But if you read them out loud, they are basically the same:
it "should have four elements"
@thing.should have(4).elements
I also often find that I can guess the right syntax which is HUGE for rapid development times. I really like rspec, and I think I am really going to like working for Planet Argon.
P.S. Backspace has awesome sandwiches.
Posted by adelcambre 513 days ago
Well I got my uncle (the delcambre.com master) to give me control of andy.delcambre.com and I installed mephisto YAY!
Haven’t really done the bloggin thing before but I thought i would give it a try.
I am currently finishing up my BS in Computer Science from Portland State University and I am looking for a job. I current work at PSU doing system administration for the Maseeh College of Engineering and Computer Science. It is a pretty good job (except the pay…) but I have decided I want to give development a try.
Anyway, keep your eye here for random stuff that interests me. I will try to stay away from being a link aggregator and stick to actually writing stuff.