May 2010 Archives

Introducing Dispatch/Highrise Integration!

| No Comments | No TrackBacks
Unless you've been living under a rock, chances are pretty good that if you're reading this blog you've also heard of 37Signals, a company that is known for making products that are powerful but simple to use. They make a product called Highrise, which is a web-based CRM, letting you keep track of people, their contact information, leads, deals and more. As of this past weekend, Dispatch integrates nicely with Highrise, so those of you who have existing Highrise accounts and want to have your contacts in both Highrise and Dispatch can do so easily. You can import your Dispatch contacts into Highrise, export your Highrise contacts into Dispatch, and even have all new contacts created in Dispatch automatically added to your Highrise account. This means that if you add a new contact in Dispatch or receive a new request from someone who's not in your Dispatch account, they automatically show up in your Highrise account. Pretty sweet! Here's how you turn on integration: For the more advanced users among you, just copy your Highrise URL and API Key into the blanks given to you on your Dispatch Settings page, check off whether you want for Dispatch to push new contacts to Highrise, and hit Save.  You can then find links to Import/Export between Dispatch and Highrise on your Contacts page. If you need a little more help with getting your Dispatch account to talk to Highrise, no sweat! Open up a text editor... TextEdit, Notepad, etc. 1. In your Highrise account, click on the Account tab. On top of the page you're sent to, you'll see a website address. Copy the bold part of that and paste it into your text file. 2. Now, click on the My info link on the top right of your Highrise account. On the page you're taken to, click the API Token link. 3. Copy your API token and paste it into your text document. 4. In your Dispatch account, go to your Settings page. 5. Look for the Highrise section, near the bottom, and paste the information that you copied into your text file into their corresponding fields. 6. If you want for Dispatch to send all new contacts created in it to your Highrise account, check the box, and save. Now, your Highrise account and Dispatch accounts are connected, and you'll find links to import/export between Highrise and Dispatch on your Contacts page and your Settings page, and Dispatch will send new contacts to Highrise automatically if you've told it to. Pretty cool!

We Love Lost is open-source!

| 8 Comments | No TrackBacks
A few days ago I had the idea to make We Love Lost, a website that celebrates the end of the TV show Lost, and I enlisted the help of an old friend/partner-in-crime, Chris Coyier to help with the front end design/development. Since I'm in the MediaTemple (ve) beta and I had a couple of servers from them that I wasn't doing anything with yet, I decided to go ahead and build a Ruby on Rails stack on top of it, including MySQL 5, Apache and Passenger. It was incredibly easy to get things going. It took me around 2 hours of setup/tweaking to get things the way I wanted on the box... then I started writing the app, which ended up taking me less time to write than it took me to configure the (ve). Also, it's fast. I've used other VPS setups recently, most notably Slicehost, and even things like installing packages just fly in comparison. It's also holding up great under the load (it loads a new tweet for everyone who has the site open, every second). What I wanted out of the website was a Rails app that would display all tweets hashtagged with #welovelost, at random, while caching them to the database for speed/archival/contest drawing purposes. I wanted for the back-end and front-end to work independently of each other (the back-end would gather new tweets every so often, and the front-end would pick a random one from the database for display). After talking with Chris, we also decided that we wanted for the random tweets to be available via JSON returned from a particular URL, so that the website wouldn't even have to be reloaded for new tweets to be displayed. I set out to build that, and it turned out to be pretty easy because decoupling of the front-end and back-ends of a service, background tasks and such is the sort of principle that we use on Dispatch to process incoming email/requests and on Are My Sites Up to check websites. Here's the Rails project and the SQL database. Download It uses the following gems, which saved me a lot of time: lockfile twitter The app consists of one controller, with 2 actions: index and show, and a back-end script that runs periodically to grab new tweets. The "index" action is the front page of the website, and in that action we grab the total number of messages in the database so we can display that on the front end... the rest of that page is all front-end dev that Chris whipped up. The "show" action is the action that serves up the JSON for a random tweet from the database, so Chris's front-end code can call that action to its heart's content and continually update the tweets without a refresh. Rails makes it super easy to return your results in JSON, but by default, if you do something like this
format.json { render :json => @message }
you'll get all fields in the database for that model returned, and some I didn't want to be public... So I did this, which gives me only the fields that I want:
format.json { render :text => @message.to_json(:only => [:screen_name, :text, :profile_image, :link]) }
Now, on the backend, in lib/get_tweets.rb, I wrote a script that gets the last tweet saved to the database, and then uses the Twitter gem to search twitter for all tweets containing "welovelost", getting the last 100 tweets, and only grabbing tweets that are newer than the last tweet saved to the database. It then saves their username, the tweet text, tweet approval, the URL of their profile image, their twitter id, and a link to the actual tweet on Twitter, by combining the Twitter URL, their screen name, and the tweet id.
ENV["RAILS_ENV"] ||= "development" #change to production on the server

require "/Users/richard/projects/welovelost/config/environment.rb" #this line is used whem running locally
#require "/home/welovelost/public_html/welovelost/config/environment.rb" #this line is used on the server

require 'net/http'
require 'rubygems'
require 'lockfile'
require 'twitter'

begin
  Lockfile.new('get_tweets.lock', :retries => 0) do
    @last_id = Message.find(:first, :order => "id desc")
    @h = Twitter::Search.new("welovelost").per_page(100).since(@last_id.twitter_id).each do |r|
      @exists = Message.find(:first, :conditions => ['twitter_id = ?', r.id])
      if @exists == nil
        @message = Message.new
        @message.screen_name = r.from_user
        @message.text = r.text
        @message.approved = "y"
        @message.profile_image = r.profile_image_url
        @message.twitter_id = r.id
        @message.link = "http://twitter.com/#{@message.screen_name}/status/#{@message.twitter_id}"
        @message.save
      end
    end

    puts "Finished running Tweet Fetcher in #{RAILS_ENV} mode"
  end
rescue Lockfile::MaxTriesLockError => e
  puts "Another Tweet Fetcher is already running. Exiting."
end
I wrap the whole thing in a lockfile call. Lockfile is a very useful gem when you're calling a script periodically via cron and want to make sure that only one instance is running at a time... I have this script being called via cron every 2 minutes, so if one run of the tweet fetcher takes longer than 2 minutes to complete, instead of starting another instance up, it'll just let the first one finish running. Here's my one line cron task that runs the tweet fetcher every 2 minutes:
*/2 * * * * cd /home/welovelost/public_html/welovelost; RAILS_ENV=production script/runner /home/welovelost/public_html/welovelost/lib/get_tweets.rb  >> /home/welovelost/public_html/welovelost/log/tweet_fetcher.log
And that, my friends is how We Love Lost was written.

Welcome.

| No Comments | No TrackBacks
Welcome to the official blog for Sense Labs. We have just released our first product, Dispatch in private beta, and this blog will be a chronicle of our (mis)adventures as we build a user base for our product/help it find its legs in the market. You'll find product news here, snippets of code/tips, things that are on our minds regarding marketing and promotion (we're new at that stuff, so it'll be a good learning experience for both us and you, our beloved readers), random thoughts passing through our heads, and much more! Take a ride with us as we try to make sense (already with the terrible jokes!) of it all.

About this Archive

This page is an archive of entries from May 2010 listed from newest to oldest.

June 2010 is the next archive.

Find recent content on the main index or look in the archives to find all content.