Facebook Application: Hello Birthday
About a month ago it was my birthday. On that day I was receiving countless e-mails from Facebook notifying me of Happy Birthday messages when I realized many of the messages followed a particular pattern (i.e. "Happy Birthday(!| <name>,| <endearing term>). Don't get me wrong, I enjoy and appreciate all of my birthday wishes. But being an Engineer, my brain finds patterns and attempts to "code up solutions." However, I had not played with the Facebook API yet and had been waiting for a good reason to come around so I took the idea of a Happy Birthday messenger to work and put together a version one of my Hello Birthday application. The application follows a few goals: to be easy to understand, easy to use, and it should just work. With that, here are the criteria I came up with to take a crack at achieving these goals:
- Automatically message friends on their birthday
- Allow enabling and disabling of such said feature
- Use a generic message that more than 50% of users observed currently use when wishing a friend "Happy Birthday"
- Manage an exclusion list, containing the friends Hello Birthday should not automatically message
- Post onto the friends' wall as if it were the user
With plans to continue development, I have a more robust friend list module going in soon and the ability to set up custom messages for particular friends. Eventually, some form of gift giving may be in order. To bootstrap development I followed a few principles:
- Prototype over masterpiece
- Design impacts implementation, but implementation makes design possible
- Low budget: use open source and free resources
To prototype the project I chose to use Ruby on Rails and SVN. To bridge my rails application and Facebook, I added the Facebooker rails plugin to my application. Facebooker is a pretty neat extension to Rails that provides all kinds of helper methods and an extremely easy to use interface wrapping the Facebook API. It also provides nice view helpers for generating FBML (the Facebook Markup Language) and FBJS (Facebook JavaScript). Developing version one locally saved quite a bit of time by realizing change immediately as opposed to any form of deployment. I then set-up a Facebook application (in Sandbox mode) for development (i.e. hello_birthday_dev) that only I had access to. Facebook offers test developer accounts, so after registering 6 or 7 of these to use with tests I was able to enumerate all of the states that Hello Birthday would need to recognize and transition.
When it came time to deploy to production I needed a production server and Facebook application. I registered the Facebook application (again, in Sandbox mode) for production (i.e. hell0_birthday) and then signed up for hosting with Heroku.com. Heroku is a Ruby (mostly Rails) cloud computing platform as a service. Basically, you get one free "cpu worker" and as you need more they sell scalable features. This, however, is perfect for what I need: a Rails host that allows cron jobs and makes deployment super fast & easy. Sure enough, Heroku makes deploying an application as easy as:
- git add .
- git commit -a
- git push heroku master
A slug of my app is created and deployed to my birthday.heroku.com production server. And to make sure I can monitor errors, I installed the hoptoad error monitoring service. Hoptoad app provides me with web-based access to error reporting and resolution management (organizes errors based on environment; test, production, and or development).
The training wheels were taken off: Sandbox mode disabled on Hello Birthday. I submitted my application to the Facebook directory a week or so ago and it's been smooth sailing since. I currently am servicing a little over 40 people. No complaints have been submitted thus far.
In summary, this is my first Facebook application and I have tried to utilize a lot of the latest technology in the process to illustrate how quickly a scalable solution to an easy problem can be solved. With Heroku & fairly efficient code, I do not foresee a problem handling a potentially high growth rate. I will try to bring back updates to this article if anything goes terribly wrong.
You can check out the Facebook application at http://apps.facebook.com/hello_birthday
Validating Emails in Ruby on Rails
It's time to validate e-mail addresses and you're sitting in a Ruby on Rails application. Fortunately, there are a few methods to tackle such a task, and a combination of them can yield a pretty nice solution.
The first idea is to use some lengthy regular expressions. But why enumerate/describe in regular expressions what we are looking for when TMail has it built in... Using TMail, it is possible to let our Ruby Net SMTP wrapper class parse the email address and decide if it is correct or not.
The second task is to make up for some of TMail's odd shortcomings: the fact that the text "bob" passes as valid for TMail is alarming, but throwing in some simple regular expression to get past this provides a pretty solid solution. (For the curious, "bob" is a valid e-mail to TMail because you could be sending messages to the local domain.)
First, here is our regular expression for a basic e-mail address...
/^([^@\s'"]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
Next, we create a TMail object with our e-mail address...
tmail = TMail::Address.parse(address.to_s) rescue nil
I am rescuing nil here. You can rescue whatever error message you want, but for example sake I am not so concerned if the TMail fails to parse the e-mail address. You can pass in a multitude of e-mail formats and TMail will do its best to match the RFC standard for e-mail addresses.
You now have access to a TMail object with a flurry of options (TMail & documentation). Let's proceed.
My simply method calls TMail and then follows it with the regular expression match to ensure this e-mail address in question is ready to be used on the web. Here is my final result to a pretty safe-proof (so far, tested on a rather large web site) e-mail handler. This method will return the TMail object.
def validate_email e-mail tmail = TMail::Address.parse(address.to_s) rescue nil tmail if tmail.address =~ /^([^@\s'"]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i end
And for those of you who want the extra step, I have attached a helper method that takes a TMail object and gives you back the e-mail address in string format fully qualified.
def formatted_email tmail if !email.blank? friendly_name = (tmail.name.blank? ? "" : tmail.name.blank?).tr('"',"'") quote = '"' if friendly_name =~ /[<,@;]/ "#{quote}#{friendly_name}#{quote} <#{address}>" end end
As always, test this code and do not trust it blindly. I could have fat fingered something...