Saturday, 27 September 2008

Wolf’s Den

This weekend, I popped by my alma mater for a few hours to briefly catch up with some people that went through the same foreign exchange program I did. Of the few (of hundreds) that brought themselves to a small, rural Wisconsin town from the far reaches of the globe – there are a handful I have a great fondness for.

These are the people that were successfully developing interfaces and other digital media professionally before I knew it was even an option. People that leave a wake.

The whole time, Hugh Macleod‘s above cartoon was stuck in my head 1.

I spent the drive home reflecting on my decade-long path and was getting a little down on myself that ‘home’ wasn’t some place ‘exotic’. That despite my many times across the ocean, I’m blocks from where my family had roots for 110 years. Making the shear possibility, of ever calling a distant land home feel more distant than ever.

Then as I pulled around the corner, the boy spotted me, and ran around the yard to greet me in the drive way. Laughing and screaming the whole way.

Home is wherever I hear his laugh.


“I’ve always, as an adult, lived in a place where I was a transplant, and other people were natives. In NY, I am a native. I actually live in the place where I come from. There are small cues. Like the smell of the ocean at sunrise, and how it reminds me of waking up in my grandmother’s house in Rockaway. ” – Dave Winer

1. The appropriate-ness of it didn’t come through until I re-read his post a few moments ago.

Wednesday, 24 September 2008

Project Launch: Best Buy Forums

I just got word one of the projects I’m involved with at Best Buy launched today:
Best Buy Forums

The team that pulled it together really ‘gets’ online communities and was a pleasure to work with.

Add this to, Giftag, and Blue Shirt Nation, and yeah, there’s a stack of very cool work happening over at the corner of 494 & 35W.

Monday, 22 September 2008

Picky Password Policy Pet Peeve

Back a few years ago, I was setting up some web apps for a friend and needed his password..

“Oh, try my non-sensitive password: ‘basketball'”

Sure enough, ‘basketball’ got me in.

That exchange was a reminder that there are different degrees of security and different comfort levels of risk associated with each of those degrees.

One persons’ ‘basketball’ is another’s ‘vaj/YfS35S)*’

This difference even exists between the service provider and the person using the service – as J Wynia describes.

Computers are really good at generating random, unguessable strings, people aren’t.

If a service has any character requirements on a password, that service should – upon request – generate passwords fulfilling those requirements. Otherwise, take what the people want to use as their password.

Sunday, 21 September 2008

Everything Else You Need to Run a Web App

As a reminder on perspective and complexity, here’s the ongoing list of systems I’ve configured for Cullect that aren’t Ruby on Rails:

  • DNS
  • Web Server: robots.txt
  • Web Server: .htaccess
  • Web Server: Virtual Domains
  • Database Server: MySQL
  • Caching Servers: Memcached, distributed across 2 boxes

And this doesn’t even crack the surface of the systems Joyent’s Jason Hoffman lists out in his Scaling Rails from the Bottom Up presentation.

A little perspective setting is always good.

There’s a network of systems all interconnected. When one of them isn’t working right, a completely other system could be the culprit. A system you’re not an expert at. A system you need a new hammer for.

Wednesday, 17 September 2008

How To: Build a Wiki with Ruby on Rails – Part 2

Back in Part 1 of Building a Wiki with Ruby on Rails, we built the core wiki engine.

Time to add some syntax formatting.

These days, I’m pretty enamored of Haml, it’s more like HTML (unlike many other formatting engines) and it’s fast to write (unlike many other formatting engines).

1. Install Haml

Haml installs as a gem…1
gem install --no-ri haml
and a plugin…
haml --rails path/to/your/wiki

2. Create Your Haml View

Open up app/views/show.html.erb
and convert it to Haml. Replacing it to:

%h1= @page.title.gsub('_', ' ')
= link_to('Edit', page_edit_path(:page_title => @page.title))
= link_to('History', page_history_path(:page_title => @page.title))
= "Last Updated #{time_ago_in_words(@page.revisions.last.created_on)} ago by #{Person.find(@page.revisions.last.person_id).name}"
%p= auto_link(@page.revisions.last.parsed_contents)

Now, your wiki should look exactly like it did before we plugged in Haml.

3. Add Haml Support for Revisions

Open up app/models/revision.rb and update def parsed_contents with:

def parsed_contents
contents = contents.gsub(/(w*_w*)/) {|match| "<a href='#{match.downcase}'>#{match.gsub('_', ' ')}</a>"}
h =

4. Try It Out

Load up a page in your wiki, click ‘edit’, and add in some simple Haml, something like:

%strong this should be bold

5. Add in Some More (non-Haml) Formatting

Once you’re comfortable with Haml, maybe add in some other simple formatting rules into revision.rb

#Auto-renders any image URL
contents = self.contents.gsub(/s(.*.(jpg|gif|png))s/, '<img src="1"/>')

# Bolds text inside asterisks
contents = contents.gsub(/*(.*)*/, '<strong>1</strong>')

# Wraps <code> around text inside '@'
contents = contents.gsub(/@(.*)@/, '<code>1</code>')

# Blockquotes text inside double-quotes
contents = contents.gsub(/s"(.*)"s/, '<blockquote>"1"</blockquote>')

# Italicizes text inside underscores
contents = contents.gsub(/s_(.*)_s/, '<em>1</em>')

6. Make it Better

After playing around with Haml and other formatting, you’ll quickly see some quirks – some room for improvement. Go for it, and let me know when you get something interesting.

1. Remember to vendor your gems.

Monday, 15 September 2008

How To: Build a Wiki with Ruby on Rails – Part 1

Here’s how to build a very simple Ruby on Rails-based wiki engine 1.

1. Create the Rails App

rails wiki
and cd wiki to get inside the app.
Remember: create your database (i.e. wiki_development) and update config/database.ymlappropriately

2. Generate the Scaffolding

There are 3 nouns in this wiki system: People, Pages, Revisions. Let’s create the models for each of them.
run script/generate scaffold Person
Now open up wiki/db/migrate/*_create_people.rb and add:
t.column "name", :string inside the create_table block to store the Person’s name.

Add Person.create :name => "First Person"
after the create_table block to give us an initial Person.

run script/generate scaffold Page
Now open up wiki/db/migrate/*_create_pages.rb and add:
t.column "title", :string inside the create_table to store the Page’s title and add
Page.create :title => "Home_Page" after the create_table block to give us an initial Page.

run script/generate scaffold Revision
Now open up wiki/db/migrate/*_create_revisions.rb and add:

# Reference to the Person that created the Revision
t.column "person_id", :integer

# The contents of the Revision
t.column "contents", :text

# Reference to the Page this Revision belongs to
t.column "page_id", :integer

3. Run the database migrations

rake db:migrate

4. Describe the relationships between the Models

People should be able to create many Revisions.
Open /app/models/person.rb and add – after the first line:
has_many :revisions

Pages should have many Revisions
Open /app/models/page.rb and add – after the first line:
has_many :revisions

Revisions should reflect they belong to both Pages and People
Open /app/models/revision.rb and add – after the first line:

belongs_to :page
belongs_to :person

5. Draw up the Routes

Open up config/routes.rb and update them to handle wiki-fied words. Copy the following after the map.resources block

map.root :controller => 'pages', :action => 'show', :id => 1

map.connect 'pages.:format', :controller => 'pages', :action => 'index'
map.connect 'revisions.:format', :controller => 'revisions', :action => 'index'

map.page_base ':title', :controller => 'pages', :action => 'show'
map.connect ':title.:format', :controller => 'pages', :action => 'show'

map.page_history ':title/history', :controller => 'pages', :action => 'history'
map.connect ':title/history.:format', :controller => 'pages', :action => 'history'

map.page_edit ':title/edit', :controller => 'pages', :action => 'edit'

Now run script/server and load up a browser.
If things are working correctly, you should see simply ‘Edit | Back’ as links

6. Create the Views

Open /app/views/revisions/new.html.erb and add

< %= f.text_area :contents %>

< % fields_for :person do |p| %>

< %= p.text_field :name %>

< % end %>

right after < %= f.error_messages %> for the Revision’s content, the corresponding Page and the author’s name
Loading up should give you the form with the text area, a text field, and a submit button you just created.

Try entering something into the form and click ‘Create’. You should see ‘Revision was successfully created.’ Now, if you pop into your database, you should see the new row in the Revisions table with the contents you entered, but NULL values for person_id and page_id.
Let’s remedy that.

Open /app/controllers/revisions_controller.rb and add this line right after the @revision declaration in both def new and def create

@revision.update_attribute('person_id', Person.find_or_create_by_name(params[:person][:name]).id)

Reload and re-fill out the form. After hitting ‘Create’ you should have another Revision record in your database with some digit in the person_id field

Now, let’s tie the Revision form we created to a Page.
Open up /app/views/revisions/new.html.erb and change the form_for to:
< % form_for @revision, :url => new_revision_path, :html => {:method => :post} do |f| %>

Next, right after < %= f.text_area :contents %> add:
< %= f.hidden_field :page_id, :value => %>

Now, rename /app/views/revisions/new.html.erb to /app/views/revisions/_new.html.erb. This turns the form into a partial, which is fine, because Revisions only exist within Pages, never on their own.
Next, replace everything in /app/views/pages/edit.html.erb with

<h1>Update "< %= @page.title.gsub('_', ' ') %>"</h1>
< %= render :partial => 'revisions/new' %>

If you load up right now, you’ll get a ‘Called id for nil’ error. That’s because the Revision partial is referencing @revision, which doesn’t exist in /pages. Yet.
Open up /app/controllers/pages_controller.rb and scroll to ‘def edit’.
Add @revision = @page.revisions.last || right after the @page declaration

Refreshing should now correctly render the form.
Fill it out, hit ‘Create’ and check the database. You should have a new record with a number in the page_id column.

But we can’t see it because doesn’t show anything.

Open up /app/views/pages/show.html.erb and add:

<h2>< %= @page.title.gsub('_', ' ') %></h2>
<p>< %= @page.revisions.last.contents %></p>
<p>last edited by < %= %> on < %= time_ago_in_words(@page.revisions.last.created_at) %> ago</p>

to the first line and save.

Refreshing should show the text you entered.

7. Update the Model, Controller, Views, and Routes to Acknowledge Wiki-fied Words (separated with an underscore ‘_’)

Open up /app/models/revision.rb and add:

def parsed_contents
contents = self.contents.gsub(/(w*_w*)/) {|match| "<a href='#{match.downcase}'>#{match.gsub('_', ' ')}</a>"}

Open up /app/controllers/pages_controllers.rb, find def show and change:
@page = Page.find(params[:id])

@page = Page.find_or_create_by_title(params[:title])
return redirect_to page_edit_url(:title => @page.title) if @page.revisions.empty?

Open up /app/controllers/revisions_controllers.rb, find def create and change each :
format.html... line to
format.html { redirect_to page_base_url(:page_title => }

Next, scroll down to def edit and change:
@page = Page.find(params[:id])
@page = Page.find_by_title(params[:title])

Now, in /app/views/pages/show.html.erb change the Edit link to build the new route:
< %= link_to 'Edit', page_edit_url(:title => @page.title) %> |

Lastly, in config/routes.rb, change
map.root :controller => 'pages', :action => 'show', :id => 1
map.root :controller => 'pages', :action => 'show', :title => 'Home_Page'

Restart your script/server and you should have a very basic wiki.

In Part 2, we’ll add formatting.

Want to see it in action? Play around with

1. There are leaner Ruby frameworks to build wikis in (Camping or Merb come to mind.). I picked Rails for 2 reasons; My servers and deployment process was already set up for Rails, I wanted to loosely integrate this wiki into another existing Rails-based application (

Sunday, 14 September 2008

McCain & Obama Tax Plans: Small Change

Viveka Weiley redrew Washington Post’s chart of Obama’s and McCain’s respective tax plans.

First off, a caveat: Basing a vote on potential personal financial changes is as one-sided as basing a vote on gender, skin pigment, or hair color. It’s one factor and one that I hope to argue it is a wash to vast majority of Americans. For both plans call for significant cuts for the vast majority of Americans – households making less than $603k/yr (99% of Americans). For those remaining 1%, taxes will either go up or down. I’m part of the 99%, and I suspect you are as well1.

Income (% of Taxpayers) Plan Difference in $ Plan Difference
as % of Income
< $603k (10) 7,869 1.3 McCain
< $227k (10) 1,591 0.7 McCain
< $161k (10) 410 0.25 McCain
< $111k (10) 281 0.25 Obama
< $ 66k (20) 723 1.1 Obama
< $ 38k (20) 779 2.0 Obama
< $ 19k (20) 548 2.9 Obama

While much attention has been made to how different these plans are at the poles, it surprises me how close the two plans are for the middle 60% of tax payers (<2% delta).

I’m assuming both plans are drafts and would have to pass Congress to be enacted 2. If so, then I assume getting them passed through Congress would change the plans – perhaps even making them more similar.

Does this betray how similar their policies are/will be for the majority of Americans?

1. If you’re not, can I has monie? kthxbye.
2. Confirming we shouldn’t be investing too much in the candidates plans:

“The fact is that presidents have no power to raise or lower taxes. They can propose tax measures or veto them but Congress has the ultimate power to raise or lower taxes” – Walter E. Williams

Thursday, 11 September 2008

Asks: Should We Buy a HD TiVo?

Our Series2 TiVo is on its last legs. With each passing day, its over-the-air recordings (we’re a no cable household) are more and more unwatchable, while digital over-the-air recordings are getting more stable. But seriously, TV without TiVo is like email without a spam filter.

Back in January, I replaced our DVD player w/ a Mac Mini. Since then, none of TiVo’s non-TV features have been used (music, podcast, etc) – simply because TiVo’s UI was too much of a PITA compared to Front Row & OS X.

The Mini’s secondary job is to play Netflix disks and does so with far fewer curse words1 than the dedicated DVD player it replaced.

In a world where; there’s a computer already plugged into our TV, NBC is back on iTunes, gaining traction, and the Roku box, dropping $200+ on a HD TiVo for over-the-air programming seems questionable.

What would you do?

The Tivo HD is now on order. Lifetime service.

1. I won’t get into my complaints about iTunes and Front Row here – they deserve their own post. 😉