My weekend project: When’s your next "fun" birthday?

When’s the next time your birthday is going to be on a Friday or Saturday, so you can go out and have fun?

That’s what my little weekend project will tell you.

This site came about because my wife and I figured out that the next time her birthday falls on a Friday, she’ll be 42 years old! Yikes.

This was a fun site to build because I got to play with some JavaScript libraries that I don’t often use, like date.js, mustache.js, and TypeWatch. I also made use of some cool CSS 3 features like @font-face with the font Tuffy Bold from Kernest. For the CSS, I used 1KB CSS Grid based on Geoffrey Grossenbach’s suggestion.

My weekend project: When’s your next "fun" birthday?

        When’s the next time your birthday is going to be on a Friday or Saturday, so you can go out and have fun?


That’s what my <a href="http://recursion.org/fun-birthday/">little weekend project</a> will tell you.


<a href="http://recursion.org/fun-birthday/"><img src="http://railspikes.com/assets/2010/3/1/fun-birthday.png" width="600"></a>


This site came about because my wife and I figured out that the next time her birthday falls on a Friday, she’ll be 42 years old! Yikes.


This was a fun site to build because I got to play with some JavaScript libraries that I don’t often use, like <a href="http://www.datejs.com/">date.js</a>, <a href="http://github.com/janl/mustache.js">mustache.js</a>, and <a href="http://plugins.jquery.com/project/TypeWatch">TypeWatch</a>. I also made use of some cool <span class="caps">CSS 3</span> features like <code>@font-face</code> with the font <a href="http://kernest.com/fonts/tuffy-bold">Tuffy Bold</a> from <a href="http://kernest.com/">Kernest</a>. For the <span class="caps">CSS</span>, I used <a href="http://www.1kbgrid.com/">1KB <span class="caps">CSS</span> Grid</a> based on <a href="http://blog.peepcode.com/tutorials/2010/about-this-blog">Geoffrey Grossenbach’s suggestion</a>.
      <img src="http://feeds.feedburner.com/~r/RailSpikes/~4/LA_L57OdoUI" height="1" width="1" alt=""/>

Using acts_as_archive instead of soft delete

        For the application I am working on right now, the ability to restore content that has been deleted is one of the requirements. A lot of people would just go ahead and add <a href="http://github.com/technoweenie/acts_as_paranoid"><code>acts_as_paranoid</code></a> or <a href="http://github.com/semanticart/is_paranoid"><code>is_paranoid</code></a> and be done with it, but I've had trouble with that approach before.

I’ve been reading a lot about the trouble with “soft deletes” (flagging a record as deleted instead of deleting it). Using a plugin that monkey patches ActiveRecord can go a long way towards fixing thesee problems, but it’s a leaky abstraction and will bite you in the ass in unexpected ways. For example, all your uniqueness validations (and indexes) become much more complicated.

That’s why Jeffrey Chupp decided to kill is_paranoid and Rick Olson doesn’t use acts_as_paranoid any more.

There are other problems too. If you delete a lot of records, and you keep them in the same table, your table

Post model

Continue reading “Using acts_as_archive instead of soft delete”

Using acts_as_archive instead of soft delete

For the application I am working on right now, the ability to restore content that has been deleted is one of the requirements. A lot of people would just go ahead and add acts_as_paranoid or is_paranoid and be done with it, but I’ve had trouble with that approach before.

I’ve been reading a lot about the trouble with “soft deletes” (flagging a record as deleted instead of deleting it). Using a plugin that monkey patches ActiveRecord can go a long way towards fixing thesee problems, but it’s a leaky abstraction and will bite you in the ass in unexpected ways. For example, all your uniqueness validations (and indexes) become much more complicated.

That’s why Jeffrey Chupp decided to kill is_paranoid and Rick Olson doesn’t use acts_as_paranoid any more.

There are other problems too. If you delete a lot of records, and you keep them in the same table, your table can get quite large, and all your queries slow down. At this point you have to use partitioning or partial indexes to get acceptable performance.

Alternatives to soft delete

In my reading, I found two alternatives to soft delete to be compelling.

The first was the suggestion to properly model your domain. Why do you want to delete a record? What does that mean? Udi Dahan puts it this way:

Orders aren’t deleted – they’re cancelled. There may also be fees incurred if the order is canceled too late.

Employees aren’t deleted – they’re fired (or possibly retired). A compensation package often needs to be handled.

Jobs aren’t deleted – they’re filled (or their requisition is revoked).

Keeping that in mind, what if the task at hand really is to delete the record? The other idea that I liked was to archive the records in another table.

The first Rails plugin I came across that implemented this was acts_as_soft_deletable which besides being misnamed doesn’t appear to be actively maintained. The author even disavows the plugin somewhat for Rails 2.3:

Before using this with a new Rails 2.3 app, you may want to consider using the new default_scope feature (or named_scopes) with a deleted_at flag.

Then I found acts_as_archive which is more recently maintained and used in production for a major Rails website.

There was only one problem — acts_as_archive didn’t support PostgreSQL. Fortunately, that was easy enough to fix.

Restoring deleted records with acts_as_archive

acts_as_archive has the ability to restore a deleted record, but only that record, not associated records.

I was troubled by this at first, but after thinking about it I came to the conclusion that restoring a network of objects is an application-dependant problem. Here’s one way to achieve it.

Imagine you have a model like this, with Posts having many Comments and Votes.

Post model

A Post can be deleted, and when it is, it should take the Comments and Votes with it:

class Post
  acts_as_archive

  has_many :votes, :dependent => :destroy
  has_many :comments, :dependent => :destroy
end

(Assume Comment and Vote also have acts_as_archive.)

Now, I can restore a Post with its associated Votes and Comments like this:

def self.restore(id)
  transaction do
    Post.restore_all(["id = ?", id])
    post = Post.find(id)

    Vote.restore_all(Vote::Archive.all(:conditions => ["post_id = ?", id]).map(&:id))
    Comment.restore_all(Comment::Archive.all(:conditions => ["post_id = ?", id]).map(&:id))
  end

In my real code, I’ve broken apart the two pieces of this into a class method restore and an instance method post_restore which the freshly restored object uses to find its associated records and restore them. post_restore also takes care of post-restore tasks like putting the object back in the Solr index.

This all works great. But now let’s say Comments can be deleted individually, and we want to restore them.

Here the logic is a little different, because a Comment can’t be restored unless its parent Post still exists (unless it’s being restored by the Post, as above).

I take care of this logic in the administrative controller, by only showing child objects that it’s valid to restore, and my foreign key constraints prevent anyone from getting around that.

I really wanted to delete that!

Sometimes you don’t want to archive a deleted object. For example, in the application I’m working on, votes are canceled by re-voting. I don’t want to save those votes — there’s no point, and it can even cause problems with restoring. Imagine having several archived votes from a user for a Post, and then deleting and restoring that Post. The restoration will try to bring back all the votes. Again, I catch this with a uniqueness constraint, but I don’t want it to happen in the first place.

Fortunately acts_as_archive has me covered.

To destroy a record without archiving it, you can use destroy!. Likewise for deleting, there is delete_all!.

Bundler and I are breaking up

        Bundler <a href="http://litanyagainstfear.com/blog/2009/10/14/gem-bundler-is-the-future/">may be the future</a>, but after way too many hours of trying to get my app working with Rails 2.3.5, <a href="http://github.com/carlhuda/bundler">bundler</a> 0.9.x, and Heroku I have decided to throw in the towel and switch back to Heroku’s gem manifest system.


I had Bundler 0.8 working very nicely but for whatever reason I couldn’t get the gems to play nice with each other in the new version. I had the app working locally and the tests passing, but on Heroku the app wouldn’t boot. This could have something to do with Heroku running Bundler 0.9.5 while I was running 0.9.7 locally. Whatever the reason, I’ve decided to take a break from bundler and wait until its development stabilizes a bit—at least on Heroku.


If you’re in the same boat, you can use this script to convert your Gemfile back to a <code>.gems</code> file and <code>config.gem</code> statements.



      <img src="http://feeds.feedburner.com/~r/RailSpikes/~4/Nf5RC-CiDVk" height="1" width="1" alt=""/>

Bundler and I are breaking up

Bundler may be the future, but after way too many hours of trying to get my app working with Rails 2.3.5, bundler 0.9.x, and Heroku I have decided to throw in the towel and switch back to Heroku’s gem manifest system.

I had Bundler 0.8 working very nicely but for whatever reason I couldn’t get the gems to play nice with each other in the new version. I had the app working locally and the tests passing, but on Heroku the app wouldn’t boot. This could have something to do with Heroku running Bundler 0.9.5 while I was running 0.9.7 locally. Whatever the reason, I’ve decided to take a break from bundler and wait until its development stabilizes a bit—at least on Heroku.

If you’re in the same boat, you can use this script to convert your Gemfile back to a .gems file and config.gem statements.

Rake task for deploying to Heroku

        Deploying to <a href="http://heroku.com/">Heroku</a> is pretty easy, but I’ve often found myself needing to do additional tasks after pushing to Heroku’s git repository. For example, if you have to migrate, you have to do that after pushing; and after migrating you have to restart the app server.


So here is a Rake task to automate that. It uses <a href="http://github.com/heroku/heroku">Heroku’s client library</a> to find the git remotes you need to push to. Use it like this:


<code>rake deploy # deploys to your default app for this directory</code>


<code>rake deploy APP=some-other-app # deploy to another app (e.g., a staging server)</code>



      <img src="http://feeds.feedburner.com/~r/RailSpikes/~4/wQKjpuHIy1w" height="1" width="1" alt=""/>

Rake task for deploying to Heroku

Deploying to Heroku is pretty easy, but I’ve often found myself needing to do additional tasks after pushing to Heroku’s git repository. For example, if you have to migrate, you have to do that after pushing; and after migrating you have to restart the app server.

So here is a Rake task to automate that. It uses Heroku’s client library to find the git remotes you need to push to. Use it like this:

rake deploy # deploys to your default app for this directory

rake deploy APP=some-other-app # deploy to another app (e.g., a staging server)

Fixing raw HTML error pages from Facebooker

        I am using <a href="http://facebooker.rubyforge.org/">Facebooker</a> for Facebook Connect with Rails 2.3.5 with the <a href="http://github.com/nzkoz/rails_xss">rails_xss</a> plugin, which escapes <span class="caps">HTML</span> by default unless you use <code>raw</code>.


I recently started seeing exceptions that looked like this:


<img src="http://railspikes.com/assets/2010/2/2/facebooker-error.png" alt="" />


The top of the <span class="caps">HTML</span> contains a <code><fb:fbml></code> tag which led me to suspect Facebooker. A quick <code>git bisect</code> confirmed this. But why is it happening?


I spent some time looking through the Facebooker source code and located the suspicious-sounding <code>facebooker_pretty_errors.rb</code> file. Sure enough, that file renders a template for errors that look good on the Facebook Canvas (assuming you’re not using rails_xss anyway…).


Fortunately, it is easy to turn this off, by setting this in your <code>facebooker.yml</code> file:
development:
  pretty_errors: true
Now it’s back to normal, and I can read my exceptions again.
      <img src="http://feeds.feedburner.com/~r/RailSpikes/~4/C4K6Aa0Ym9o" height="1" width="1" alt=""/>

Fixing raw HTML error pages from Facebooker

I am using Facebooker for Facebook Connect with Rails 2.3.5 with the rails_xss plugin, which escapes HTML by default unless you use raw.

I recently started seeing exceptions that looked like this:

The top of the HTML contains a <fb:fbml> tag which led me to suspect Facebooker. A quick git bisect confirmed this. But why is it happening?

I spent some time looking through the Facebooker source code and located the suspicious-sounding facebooker_pretty_errors.rb file. Sure enough, that file renders a template for errors that look good on the Facebook Canvas (assuming you’re not using rails_xss anyway…).

Fortunately, it is easy to turn this off, by setting this in your facebooker.yml file:

development:
  pretty_errors: true

Now it’s back to normal, and I can read my exceptions again.

Fixing the Heroku "Too many authentication failures for git" problem

        Getting an error like this when you push to Heroku?
electricsheep:herokuapp look$ git push heroku master
Received disconnect from 75.101.163.44: 2: Too many authentication failures for git
fatal: The remote end hung up unexpectedly
If you like to create an ssh key for each server you use, you run this risk.


The reason is that unless you specify which key to use for a host, ssh-agent sends each key in turn until one works. However some server configure sshd to reject connections after too many attempted logins. For example, Dreamhost does this (see <a href="http://adterrasperaspera.com/blog/2009/03/15/dealing-with-sshs-key-spam-problem">Dealing with <span class="caps">SSH</span>’s key spam problem</a> for details). This is especially annoying if you weren’t even planning to use key-based authentication (as is the case on Heroku).


You can fix this by setting <code>IdentitiesOnly yes</code> in your <code>~/.ssh/config</code> file. You can do this on a host-by-host basis.
host foobar.dreamhost.com        
        IdentitiesOnly 
Continue reading "Fixing the Heroku "Too many authentication failures for git" problem"

Fixing the Heroku "Too many authentication failures for git" problem

Getting an error like this when you push to Heroku?

electricsheep:herokuapp look$ git push heroku master
Received disconnect from 75.101.163.44: 2: Too many authentication failures for git
fatal: The remote end hung up unexpectedly

If you like to create an ssh key for each server you use, you run this risk.

The reason is that unless you specify which key to use for a host, ssh-agent sends each key in turn until one works. However some server configure sshd to reject connections after too many attempted logins. For example, Dreamhost does this (see Dealing with SSH’s key spam problem for details). This is especially annoying if you weren’t even planning to use key-based authentication (as is the case on Heroku).

You can fix this by setting IdentitiesOnly yes in your ~/.ssh/config file. You can do this on a host-by-host basis.

host foobar.dreamhost.com        
        IdentitiesOnly yes

Heroku is a bit difficult to do this for because they don’t have a single IP address or domain (that I know of) you can configure this for.

As a workaround, clear your identities:

ssh-add -D

(Thanks to my friend McClain for his help with the ssh-add command.)

Editing Migrations

        I have a confession to make: when I’m starting out a new project, especially if it’s a small team, I like to edit my migrations.


At the beginning of a project there are always a ton of changes in how models are defined and how they relate to one another. I find it so much easier to edit migrations and keep these initial declarations compact than to write new migrations for every piddling change.


The downside is an increased communications burden—people need to know they need to run <code>rake db:migrate:reset</code> when migrations change. And, of course, once you’ve got real data in production, you can’t do this.


But at the beginning of a project, I like to edit my migrations.
      <img src="http://feeds.feedburner.com/~r/RailSpikes/~4/thaoMs0WGlA" height="1" width="1" alt=""/>

Editing Migrations

I have a confession to make: when I’m starting out a new project, especially if it’s a small team, I like to edit my migrations.

At the beginning of a project there are always a ton of changes in how models are defined and how they relate to one another. I find it so much easier to edit migrations and keep these initial declarations compact than to write new migrations for every piddling change.

The downside is an increased communications burden—people need to know they need to run rake db:migrate:reset when migrations change. And, of course, once you’ve got real data in production, you can’t do this.

But at the beginning of a project, I like to edit my migrations.

Y Combinator Interview Advice

        Paul Graham emailed YC co-founders to share their interview stories for those who were asked to interview for the W10 batch. Here’s my take.

First off, congratulations! You’re probably wondering what to do next, depending on the outcome of the interviews. I’m not going to tell you not to be nervous, because that won’t help. But keep perspective – YC’s not the end-all of the startup world. If you’re dedicated, you can make your company happen (startups did exist before YC, believe it or not). I know one team that got rejected, but decided to move to Silicon Valley anyway. They got funded by a major VC before most of the companies in the Summer 2009 batch!

That said, Y Combinator is an…intense experience and you should try your hardest to get in.

What to expect

I can’t say what to expect better than Paul, so be sure to

Continue reading “Y Combinator Interview Advice”

Y Combinator Interview Advice

Paul Graham emailed YC co-founders to share their interview stories for those who were asked to interview for the W10 batch. Here’s my take.

First off, congratulations! You’re probably wondering what to do next, depending on the outcome of the interviews. I’m not going to tell you not to be nervous, because that won’t help. But keep perspective – YC’s not the end-all of the startup world. If you’re dedicated, you can make your company happen (startups did exist before YC, believe it or not). I know one team that got rejected, but decided to move to Silicon Valley anyway. They got funded by a major VC before most of the companies in the Summer 2009 batch!

That said, Y Combinator is an…intense experience and you should try your hardest to get in.

What to expect

I can’t say what to expect better than Paul, so be sure to read Y Combinator’s advice. There’s also been a number of YC alumni sharing their stories – check the bottom of that link. I’ll especially call out Michael Young’s experience because he didn’t get accepted…then joined a team that did, so he’s seen both sides.

The interview setup itself is intimidating: you and your co-founders are sitting face-to-face with the Y Combinator partners (Paul, Jessica, Trevor, and Robert) across a ridiculously narrow table. In our interview, that tension was quickly broken as everyone crowded around to see our demo. Paul thinks big, so if he likes your idea, be prepared for him to rattle off about 2 years worth of work for you to do – new features, new markets, a different direction, etc.

However, it’s not all about the idea. Some teams get roughed up in the interview and are surprised to be accepted. The Y Combinator partners are looking for teams to fund. Lots of YC startups end up doing a totally different thing before Demo Day.

After the interview, be prepared for some of the longest hours of your life as you wait for the email (rejected) or phone call (accepted).

Getting Ready

“What are you going to do?” This is the number one question to have an answer for. One sentence. Two tops. I made my co-founder repeat our answer ad nauseam for practice. You know how hard it was to boil your idea down into the 1 minute video for your application. Now it’s time to distill it even further. This is your first elevator pitch. Also be ready to talk about your competitors and how you’re going to make money.

Your demo. You are going to show your demo. You’ve got some time: polish it up! Fix rough edges, improve the UI, add the cool new feature you’ve been thinking about, test the critical paths. Could you sign up a paying customer before the interview? That’s impressive.

I was in charge of giving the demo. I decided to do it as a series of browser tabs showing different features, because then I wouldn’t have to worry about the internet connection or anything breaking. I practiced it relentlessly and got it down to about a 2 minute spiel. When I actually showed the YC partners, I got interrupted and had to explain things here and there but I knew the material and was able to carry on.

Mock interviews. We set up some mock interviews with entrepreneurs to practice. We wanted people who had run successful startups to test us and see where the weakness in our company and idea were.

Scott Wheeler of Direct Edge writes about something similar they did:

We brainstormed a big list of questions that I can’t find anymore that we thought might come up and talked through answers to all of them. We came up with a list of points that we wanted to be sure to mention and even practiced transitions from other topics to those.

All of that, however, turned out to be useless.

Our mock interviews turned out nothing like the real one. But I disagree with Scott. It wasn’t useless, because it made us more prepared.

If you’re prepared, you’ll be more relaxed, and can focus on presenting your idea.

Talk to alumni. You probably know some YC alumni. Email them and see try to set up a phone call about what to expect. I think you’ll find most will be happy to give you some time to ask questions.

Good luck

That’s it for now. Maybe someday I’ll tell the full story of our YC interview (which includes nearly missing it due to a Murphy-worthy series of screwups) but for now I wanted to get the solid advice out of the way.

Not everyone is going to get in, but if you focus on “What are you going to do?” and getting your demo down cold, you can maximize your odds.

Weird Gem Error

        Talk about a hard problem to diagnose!


I canceled the installation of Rack 1.0 half way through because I realized I was running the wrong command (I didn’t use <code>sudo</code> like I wanted to).


After that, I couldn’t load rack at all, even though I could see it in my gems directory and I could load other gems there. I got a LoadError, like this:
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'rack'
LoadError: no such file to load -- rack
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from (irb):2
I tried downgrading Rails to the version that used Rack 0.9.1 and then I got an error saying Rails couldn’t activate Rack 0.9.1 because 1.0.0 was already active!


Finally figured it out—there was a gemspec for rack-1.0.0 in my <code>~/.gems</code> directory, but no corresponding gem in the lib directory. Ugh!
      <img src="http://feeds.feedburner.com/~r/RailSpikes/~4/dje2MF31MFo" height="1" width="1" alt=""/>

Weird Gem Error

Talk about a hard problem to diagnose!

I canceled the installation of Rack 1.0 half way through because I realized I was running the wrong command (I didn’t use sudo like I wanted to).

After that, I couldn’t load rack at all, even though I could see it in my gems directory and I could load other gems there. I got a LoadError, like this:

irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'rack'
LoadError: no such file to load -- rack
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from (irb):2

I tried downgrading Rails to the version that used Rack 0.9.1 and then I got an error saying Rails couldn’t activate Rack 0.9.1 because 1.0.0 was already active!

Finally figured it out—there was a gemspec for rack-1.0.0 in my ~/.gems directory, but no corresponding gem in the lib directory. Ugh!

validates_length_of byte counting gotcha

        Watch out for <code>validates_length_of</code> if you need to make sure a string is a certain number of <em>bytes</em> long. For example, <span class="caps">SMS</span> messages can be no longer than 160 bytes in length. I recently got bit by this because some unicode “curly” quotes slipped into a reply message, but they weren’t detected by the validation.


Here’s the problem.


Consider this string:


<code>str = "€"</code>


It is 3 bytes long:


<code>str.size => 3</code>


However, ActiveRecord’s <code>validates_length_of</code> records this as only one character, because it uses <code>str.split(//).size</code> to measure the size.


If you <span class="caps">NEED</span> to be certain that a string is less than a certain number of bytes, you’ll need to override the default behavior of <code>validate_length_of</code>.


Fortunately, you can supply your own tokenizer, which makes this easy. The tokenizer is called, and <code>size</code> is called on its return value to find out how many tokens there are. Since <code>
Continue reading "validates_length_of byte counting gotcha"

validates_length_of byte counting gotcha

Watch out for validates_length_of if you need to make sure a string is a certain number of bytes long. For example, SMS messages can be no longer than 160 bytes in length. I recently got bit by this because some unicode “curly” quotes slipped into a reply message, but they weren’t detected by the validation.

Here’s the problem.

Consider this string:

str = "€"

It is 3 bytes long:

str.size => 3

However, ActiveRecord’s validates_length_of records this as only one character, because it uses str.split(//).size to measure the size.

If you NEED to be certain that a string is less than a certain number of bytes, you’ll need to override the default behavior of validate_length_of.

Fortunately, you can supply your own tokenizer, which makes this easy. The tokenizer is called, and size is called on its return value to find out how many tokens there are. Since String responds to size which returns the number of bytes, you can simply return the attribute value itself as the tokenizer, like this:

validates_length_of :message, :maximum => 160, :tokenizer => lambda { |str| str }

Will this still work in Ruby 1.9? I’m not sure. I now have a test case which will warn me if it doesn’t…