We're proud that Donor Tools has been featured in Web Designer Depot! This time our back-end user interface is featured, not just our home page. Web Designer Depot has a Showcase of Great Web App Interfaces featuring Donor Tools among some really good company, including Xero, MailChimp, and more. Go check it out!

Other galleries that Donor Tools has been featured in include:


all?

July 4th, 2009

1
2
3
4
5
6
7
8
9
10
11
>> [true, false].all?
=> false
>> [true, true].all?
=> true

>> [true, true].any?
=> true
>> [true, false].any?
=> true
>> [false, false].any?
=> false

We do a lot of data migrations for Donor Tools – a lot of folks are coming to us from other systems, and they need their data ported over. Depending on the kind of system they were using, this can be anywhere from a quick script to a major data transformation headache.

Recently I needed a quick way to parse a full name string into name parts. Given a name like “Dr. Joe Donor, M.D.”, I wanted to end up with a name object with a prefix of “Dr.”, a suffix of “M.D.”, a first name of “Joe”, and a last name of “Donor”. Complicating matters, it also needed to be able to handle odd permutations like “Dr. and Mrs. Joe and Jane Donor”, etc.

The main problem that I had was with the “and”. If there was an “and”, it should put the preceding and following words together to form a single word. This turned out to be nearly impossible with regular expressions, but pretty easy with a combination of Ruby and regex. Here’s how it looks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Name < ActiveRecord::Base

  def self.parse(name)
    return false unless name.is_a?(String)
    
    # First, split the name into an array
    parts = name.split
    
    # If any part is "and", then put together the two parts around it
    # For example, "Mr. and Mrs." or "Mickey and Minnie"
    parts.each_with_index do |part, i|
      if ["and", "&"].include?(part) and i > 0
        p3 = parts.delete_at(i+1)
        p2 = parts.at(i)
        p1 = parts.delete_at(i-1)
        parts[i-1] = [p1, p2, p3].join(" ")
      end
    end
    
    # Build a hash of the remaining parts
    {
      :suffix => (s = parts.pop unless parts.last !~ /(\w+\.|[IVXLM]+|[A-Z]+)$/),
      :last_name  => (l = parts.pop),
      :prefix => (p = parts.shift unless parts[0] !~ /^\w+\./),
      :first_name => (f = parts.shift),
      :middle_name => (m = parts.join(" "))
    }
  end

end

Here’s the output:

1
2
3
4
5
6
7
8
9
10
11
Name.parse "Mr. Joe Donor"
=> {:middle_name=>"", :prefix=>"Mr.", :last_name=>"Donor", :suffix=>nil, :first_name=>"Joe"}

Name.parse "Dr. and Mrs. Joe Donor, M.D."
=> {:middle_name=>"", :prefix=>"Dr. and Mrs.", :last_name=>"Donor,", :suffix=>"M.D.", :first_name=>"Joe"}

Name.parse "Joe and Jane Donor"
=> {:middle_name=>"", :prefix=>nil, :last_name=>"Donor", :suffix=>nil, :first_name=>"Joe and Jane"}

Name.parse "Joe and Jane Major-Donor"
=> {:middle_name=>"", :prefix=>nil, :last_name=>"Major-Donor", :suffix=>nil, :first_name=>"Joe and Jane"}

Gist First Impressions

May 6th, 2009

After publicly swooning over Gist, I finally got my Gist invite yesterday! What a treat! I wanted to share a few quick first impressions.

First impression is that this is really, really cool. I put in a couple key bits of information, and it started sucking down my friends and followers (doesn’t that make me sound cool). After a while it had imported all my contacts, and put together a sort of aggregate “wall” for each.

Since many of my contacts were from Twitter, many have just their tweets in their contact wall. For example, I follow Guy Kawasaki, and since he doesn’t know I exist all I have on his wall is his prolific list of recent tweets. This is minorly useful, but I think it will start to get a lot more informative after I hook in more services and provide more detail about my contacts. However, for a few of my contacts I have a lot more information, such as rss feeds and such, which makes their contact record bristle with information.

One of the things I’m hoping for is Apple Mail integration. Currently they have an Outlook plugin, which looks promising but doesn’t work for me as a Mac user. Also, I had a bit of trouble connecting to my Google Apps account. Might have been a PBKAC (Problem Between Keyboard And Chair) error though.

All in all I’m very impressed. They’ve got an awesome service and I can’t wait to see how it develops.


Donor Tools is Growing

May 5th, 2009

This is an exciting time for Donor Tools! We’re growing, and I’m so pleased to welcome Chris Dumas to the Donor Tools team!

Chris is joining Donor Tools to head up business development. Chris has a tremendous amount of positive energy, and he knows his stuff. This is an exciting time at Donor Tools. We’re growing, momentum is building, and we’re excited about the new things that we have to offer in the coming months.

Read Chris’ remarks over on the Donor Tools blog →

Welcome Chris! It’s great to have you on board!


Gist

May 5th, 2009

I am itching to try Gist. The idea, as I understand it, is that Gist gives you a web’s-eye view of the people who you email with. So you could see blog articles, tweets (maybe?), news, etc. about the person who just sent you a message. Pretty idea.

I haven’t gotten my invite yet, but I’m waiting with baited breath (hint hint). I’ll be sure to let you all know how it goes if I get an early invite to the beta.


Web Forms: Submit or Save?

March 23rd, 2009

Submit (v) 1 [ intrans. ] accept or yield to a superior force or to the authority or will of another, 2 [ trans. ] present (a proposal, application, or other document) to a person or body for consideration or judgment…

Save (v): 1 [ trans. ] keep safe or rescue (someone or something) from harm or danger, 2 keep and store up (something, esp. money) for future use…

Hmmm…

Source: Mac OS X Dictionary


Rearrange Your OS X Menu Bar

February 9th, 2009

Did you know you can rearrange the icons in your menu bar in OS X? I just figured this out by accident. Hold down the Command key, and drag the icon to move it. If you drag it out of the menu bar, it will poof and go away. Boom!

Apparently the only icon that can’t be moved is the Spotlight icon. It’s a super icon.


application/octet-stream WTF?

December 17th, 2008

Lately I’ve been having this problem with uploaded files using the Paperclip plugin (though I don’t think it has anything to do with the plugin).

My customers are trying to upload CSV files to their Donor Tools account. Normally, when you upload a .csv file, the content type is set to “text/csv” or some variation of “text/*”.

Here’s the problem: when uploading .csv files in Windows using any version of IE or Firefox, the content type is set to “application/octet-stream”.

What the flip?

This only occurs with IE or Firefox. Safari for Windows uploads the exact same file with the content type set correctly to “text/csv”.

To get around the problem I’ve temporarily turned off the file type validation, which I don’t like because I really don’t want to be accepting uploaded binary files.

Has anyone seen this problem before? How did you deal with it?


Have a big migration that would take too long to complete? It would be too bad to inadvertently bring down your whole server by loading a big dataset into memory.

A very simple solution is to use will_paginate. I was just combing through the plugin code, and found out that will_paginate has a nice method called paginated_each, which “Iterates through all records by loading one page at a time. This is useful for migrations or any other use case where you don’t want to load all the records in memory at once.”

So instead of writing for article in Article.find(all), you’re better off using Article.paginated_each do |article|. Your migrations will finish faster and with less memory usage.


I hate to admit it, but I have lost documents while working on my mac. You know how it happens – typing a long document in Pages, with 35 tabs open in Safari, checking Mail, downloading attachments, then open Photoshop and… Boom. It crashes. And I forgot to save.

Strangely, there is no auto-save feature in Apple Pages or Keynote, nor any number of other OS X apps. TextMate has this feature, and I rely heavily on it. Every time I make a change to a file, I switch to the browser to check it out, and TextMate automatically saves my file. I barely even think about it, until it’s not there.

Today I discovered EverSave, a free app that auto-saves your documents for you.

EverSave is a clever tool which allows you to save all of your documents – if possible – in a specific time interval or by changing the frontmost application. This means no more data loss if applications crash.

This should definitely be built into all new OS X apps.

Download it here


Spike

October 31st, 2008

Wow! Donor Tools peaked at almost 2000 visitors yesterday thanks to linkage from Best Web Gallery and CSS Mania


Parenting Theory

October 31st, 2008

As our children are developing into ever more sophisticated and rational human beings, we are degenerating – devolving into shadowy cave-people, with heightened reflexes but incapable of forming a complete sentence or retaining a memory for more than 15 seconds. No. Complete. Sentence. Ungh! But! We can catch a glass jar tipped by a toddler as it hurtles its way to the ground. Me kung-fu cave dad.


Here’s a quick and easy way to track exactly where your signups are coming from, and who referred any given customer, without having to cross-reference your analytics program.

1
2
3
4
5
before_filter: set_referer

def set_referer
  cookies[:referer] = request.env['HTTP_REFERER'] if cookies[:referer].nil?
end

The set_referer method sets up a session variable that keeps the original referrer with your customer, no matter how many pages they click through before signing up.

You can email this variable to yourself when they sign up, or store it in the database to keep track of who came from where.


Ryan Bates has a helpful screencast about the using the excellent Thinking Sphinx Rails plugin for the Sphinx search engine.

There seems to be a bit of confusion over how to enable wildcard (star) searches with Thinking Sphinx. Wildcard searches would let you search for partial words, so “thin*” would match “Thinking Sphinx” and “Thinner”. This is pretty useful, and for Donor Tools it is essential.

Turns out it’s really easy to turn on wildcard search. There is no need to make any changes to your Sphinx setup or add a config/sphinx.yml file. In your define_index block, simply add enable_star and min_prefix_len like so:

1
2
3
4
5
define_index do
  ...
  set_property :enable_star => true
  set_property :min_prefix_len => 3
end

enable_star simply turns on wildcard searching. However, this won’t do much good unless you also enable prefix indexing using min_prefix_len.

min_prefix_len sets the minimum number of letters that Sphinx will index. From the Sphinx docs:

...indexing a keyword “example” with min_prefix_len=3 will result in indexing “exa”, “exam”, “examp”, “exampl” prefixes along with the word itself.

You can also set min_infix_len, which does the same thing as min_prefix_len, except it does it on the middle of the word.

Infix indexing allows to implement wildcard searching by ‘start*’, ’*end’, and ’*middle*’ wildcards.

Caution: Infix indexing can cause your index to grow, and may slow down searching.

Now, re-run rake thinking_sphinx:configure, re-index (rake ts:in), and restart the Sphinx daemon (rake ts:run), and it should work.