Navigation

ADS specializes in using Ruby on Rails to build advanced, scalable, database-backed web sites for organizations of all sizes. Find out more at our website.

Atlantic Dominion Solutions

In the past importing Gmail contacts was a bit of a hassle. One of the previous options was to use the Contacts gem found at RubyForge. However, now that the Google Contacts API has been released, it offers a more secure (and hopefully reliable) way to retrieve contacts. The Contacts API allows redirecting and authenticating users through Google, instead of forcing them enter their Gmail password into a third party application. Here is a quick tutorial to get up and running in ruby on rails with the Gmail Contacts API.

First, you need to register your domain with Google. This can be as easy as uploading a temporary file to your domain’s root directory to verify control of the domain. The steps for doing this are clearly outlined at Registration for Web-Based Applications.

Once you’ve verified control of the domain with google, start making your requests! Grabbing the contacts is essentially a three step process:

  • Initiate the authentication with Gmail. Send your user over to enter their credentials, after which Google passes back an AuthSub token valid for one request.
  • Send back the one-time AuthSub token and exchange it for a long-lived token valid for multiple requests.
  • Use this second token to make requests to the Gmail Contacts API and import user’s Gmail contacts.

    More detailed steps on how Google Authentication process works can be found at Authentication for Web Applications

Now lets visit the three steps above in more detail, and implement importing gmail contacts using ruby on rails!

1. First redirect your users to authenticate with Gmail and request a one-time use AuthSub token.

# initiate authentication w/ gmail
  #
  # create url with url-encoded params to initiate connection with contacts api
  #
  # next - The URL of the page that Google should redirect the user to after authentication.
  # scope - Indicates that the application is requesting a token to access contacts feeds. 
  # secure - Indicates whether the client is requesting a secure token.
  # session - Indicates whether the token returned can be exchanged for a multi-use (session) token.
  #  
  next_param = "http%3A%2F%2Fwww.example.com%2F"
  scope_param = "http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2F"
  secure_param = "0"
  session_param = "1"
  root_url = "https://www.google.com/accounts/AuthSubRequest"
  query_string = "?scope=#{scope_param}&session=#{session_param}&secure=#{secure_param}&next=#{next_param}"
  redirect_to root_url + query_string

2. Trade your single-use token for the all powerful AuthSub session token.

  require 'net/http'
  require 'net/https'
 
  token = params[:token] # received the single-use authsub token, exchange for authsub session token
 
  http = Net::HTTP.new('www.google.com', 443)
  http.use_ssl = true
  path = '/accounts/AuthSubSessionToken'
  headers = {'Authorization' => "AuthSubtoken=\"#{token}\""}
  resp, data = http.get(path, headers)
 
  if resp.code == "200" 
    token = ''
    data.split.each do |str|
      if not (str =~ /Token=/).nil?
        token = str.gsub(/Token=/, '')   
      end
    end
    redirect_to "http://www.example.com/?token=#{token}"
  else  
    redirect_to "http://www.example.com/"
  end

Note: There’s probably a better way to grab the above token from the response, if anyone would like to suggest a refactoring here please feel free . . .

3. Finally, grab your buddies!

# GET http://www.google.com/m8/feeds/contacts/default/base
require 'net/http'
require 'rexml/document'      
 
http = Net::HTTP.new('www.google.com', 80)
# by default Google returns 50? contacts at a time.  Set max-results to very high number
# in order to retrieve more contacts
path = "/m8/feeds/contacts/default/base?max-results=10000"
headers = {'Authorization' => "AuthSubtoken=\"#{authsub_token}\""}
resp, data = http.get(path, headers)
 
# extract the name and email address from the response data
xml = REXML::Document.new(data)
contacts = []
xml.elements.each('//entry') do |entry|
  person = {}
  person['name'] = entry.elements['title'].text
 
  gd_email = entry.elements['gd:email']
  person['email'] = gd_email.attributes['address'] if gd_email
 
  contacts << person
end

Hopefully that should help get you started on the right track. The Google Contacts API allows retrieval of other information besides simply name and email address. I’d be interested in hearing what else is everyone using/doing with this API?

Share this post

So you’ve built a downright amazing website. It is compatible with Internet Explorer, Firefox, Safari, and even WebTV! But, is it compatible with google search results? Huh, why does this matter? Well it may or may not actually, depending on your site, but if you plan on getting clicks from Google and other search engines, there are a few things you should be putting into practice to maximize your results. Take a look at these two search listing examples shown below.

Listing Number 1:

Atlantic Dominion Solutions

ruby (5); Ruby Web Developer (5); RubyConf (1); The New Web (9); Tips (5); Tutorial (2); Uncategorized (1); Women in Computing (1). Our Favorite Links

rorblog.techcfl.com/ - 134k - Cached - Similar pages - Note this

Listing Number 2:

2 Easy Tips that can Make or Break your Google Search Listing

Tips for making the most of your google search engine listing that everyone interested in search engine optimization should be applying. Examples in Ruby on Rails

rorblog.techcfl.com/ - 134k - Cached - Similar pages - Note this

Which one looks more enticing, the first result or the second? Even with a higher ranking, the first result may be getting passed over in favor of the second result which clearly describes its content. If your not setting your title and META tags correctly, you may be missing out on extra clicks. Lets explore how:

  • Customize your page title - This often shows up as the search listing title. Look at the effect this has on the two listings! It is so important to have customized page titles which let users immediately know the value your website provides.

  • Add a META tag description - This helps the search engine generate a description for your search result listing. These should also be customized per page and go along with the page title. Here is an example of how to set up a META tag with a description:

    <META NAME="description" CONTENT="Tips for making the most of your google search 
    engine listing that everyone interested in search engine optimization should be
    applying.  Examples in Ruby on Rails . . ./>
  • While your at it, go ahead and toss in some META tag keywords. Most seo professionals agree the major search engines place little value on these tags, however it certainly cannot hurt as long as their not abused. Also, some of the smaller search engines still rely on these tags to classify results. Here is how to add a META tag for keywords:

    <META NAME="keywords" CONTENT="search engine optimization, seo, ruby on rails, 
    META tags"/>

No matter how hard you try, sometimes the META tags just won’t stick in the search listings. More often than not however, they can be used to help better describe your website to potential viewers. This can both attract more visitors to the website, and leave visitors with a more satisfied viewing experience. A win-win situation!

Share this post

Trying to make sense of the Google App Engine and what possibilities it holds I have compiled a list of what seems to be good, bad, and what I’m not quite sure about.

First, what seems bad:

Some Bad Things

  1. You can not access the file system.
  2. You can not run background processes, not even CRON.
  3. You can not spawn off another thread / process.
  4. Requests that take more than a few seconds are terminated (why would you do this to your users anyway?).
  5. You are only able to access other sites and services using HTTP(S), so no fancy sockets or anything like that (this doesn’t seem bad, but it is a limitation).
  6. You can’t use the Django authentication, admin, or session middleware apps (more on this below).
  7. You can not use Django models.
  8. Some standard libraries have been disabled, so not all Python modules are available.
  9. As of right now, you can not use Ruby, PHP, C#, Java, or anything else. Only Python (is that so bad actually?).

Some Good Things

  1. You use Python.
  2. You can use Django.
  3. It uses Googles DataStore and they provide a nice API (it’s similar to Django models).
  4. The Django admin and authentication is handled by Google.
  5. It scales.
  6. Deploys fast and easy.
  7. Monitoring is part of the admin console provided by Google.
  8. You can include any pure Python libraries when you upload your application.

Some Things I am Unsure About

  1. Vendor lock-in? If I want to move my app someplace else for example.
  2. How is domain management handled?
  3. GQL? I’m not sure what to make of it, except it looks like SQL. Are there any Limitations compared to SQL?

How does this compare to Amazon’s web developer services? Well, it seems the 2 services are not really comparable.

The only thing that seems to compare is the hosting platforms, that is EC2 and the whole GAE package. An EC2 instance is like a VPS, you have much more control (what gets installed, libraries, languages, database, etc). Setting up an EC2 instance is not difficult, but definitely not as easy as using GAE. If you like Python and don’t have any issues with the limitations Google has with it’s sandbox it seems like a great service. Actually it’s a great service regardless of those limitations.

Regarding S3 and SimpleDB, I don’t see how Google is even competing or offering a similar service with GAE. Did I miss something? These 2 services can be used from anywhere on the internet. As far I can tell, GAE does not have any sort of S3 equivalent and DataTable seems limited to being used inside GAE only.

Regardless of any of it’s current limitations, Google App Engine seems like a very cool neat service and I can’t wait to take advantage of it someday.

My question now is what type of apps can take advantage of this service?

Oh, and if you aren’t a big fan of Django for some unknown various reason, you can always try Pylons.

Share this post