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'

  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}"

    puts "Finished running Tweet Fetcher in #{RAILS_ENV} mode"
rescue Lockfile::MaxTriesLockError => e
  puts "Another Tweet Fetcher is already running. Exiting."
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.

No TrackBacks

TrackBack URL: http://staging.madewithsense.com/cgi-bin/mt/mt-tb.cgi/13


This makes a lot of sense. Looks like the next semester break would be spent either with RoR or Django. Both languages seams so logical for a guy who only have PHP experience.

I have been thinking about "upgrading" my GS to VE since the price difference is so minimal. The more I read about the VE the more convinced I get.

Nice work.. I love the app!

Blogengine FTW! Domino's Pizza | DOMINO¡¯S PIZZA¡¯S NOW OPEN IN CHESTER is cool.  I am really interested and was wondering if anyone else had any other related posts they could suggest. I like writing squidoo lenses myself and would like to gather as much data as I can. Please take a look one of my little projects if you like

,buy windows vista online

Hey there,discount office 2003! This is kind of off topic but I need some guidance from an established blog. Is it difficult to set up your own blog? I'm not very techincal but I can figure things out pretty quick. I'm thinking about setting up my own but I'm not sure where to start. Do you have any tips or suggestions?  Cheers

,baltimore ravens jerseys

Hey there,miami dolphins jerseys! This is kind of off topic but I need some guidance from an established blog. Is it difficult to set up your own blog? I'm not very techincal but I can figure things out pretty quick. I'm thinking about setting up my own but I'm not sure where to start. Do you have any tips or suggestions?  Cheers

It's a pity you don't have a donate button,Trent Edwards Jersey! I'd most certainly donate to this brilliant blog,Matt Jersey! I guess for now i'll settle for bookmarking and adding your RSS feed to my Google account. I look forward to fresh updates and will share this blog with my Facebook group. Talk soon,Eli Manning Jersey!

I run my own siteand I came here by mistake. I read your articles and I found that they're super,Gonzalez Jersey! I would like to use them on my site. I want do that without your agreement,bears jerseys, so say OK. I'm greeting warmly.

It really is a great idea.I will have a trial of this idea as soon as I got the pattern.Thank you for constantly posting of so many useful tips.They are such a great help to me.Thank you very much,Johnny Jersey!

Leave a comment

About this Entry

This page contains a single entry by Richard Felix published on May 16, 2010 1:41 AM.

Welcome. was the previous entry in this blog.

Introducing Dispatch/Highrise Integration! is the next entry in this blog.

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