Flickr Panda – a mashup written in Ruby on Rail and Ajax
Flickr is one of the largest online photo management and sharing application which claims to host more than 3.6 billion of images as June 2009. Flickr provides APIs for outside developers to develop mashup application which can interact with Flickr services. Flickr Panda is a set of AIPs allows users to take a list of recent public and safe photos.
In web development, a mashup is "a web page or application that combines data or functionality from two or more external sources to create a new service. The term mashup implies easy, fast integration, frequently using open APIs and data sources to produce results that were not the original reason for producing the raw source data.
An example of a mashup is the use of cartographic data from Google Maps to add location information to real estate data, thereby creating a new and distinct Web service that was not originally provided by either source.
Below is a step by step instruction to develop a simple Flickr Panda mashup application using in Ruby on Rail and Ajax.
Installation and configuration
Install Ruby on Rail:
The easy way to install Ruby on your machine is to visit download section of rubyonrails.org, and download the bundle  install package, then download and install RubyGem.
When you have Gem installed, then you can install Rails by command:
gem install rails
Configure MySQL
By default, ROR bundle comes with a light weight database carrier call SQLite but I think that many web developers are fans of MySQL. To install MySQL :
gem install mysql
After installing MySQL, when you start your application, you may suffer the following error:
"!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again: gem install mysql."
The problem is because MySQL 5.1 client library doesn't play well with Rails - the solution is simple however:
- download older MySQL client library, for example one from InstantRails: http://instantrails.rubyforge.org/svn/t ... bmySQL.dll
- copy the downloaded file to C:\Ruby\bin (or wherever you installed Ruby)
Create ROR application
rails flickr
The above command will generate a ROR standard directory structure


Change the configuration of the database in Rails application:
Browse to flickr/config, open the file database.yml  by wordpad and make some change:
#Â Â gem install
development:
adapter: mysql
database: ruby
encoding: utf8
username: root
password: admin
host: localhost
* You may need to change the values database, username and password to the setting on your machine
Start webrick server:
In flickr directory:
ruby script/server
By default, webrick server will start on port 3000, open a web browser and type in:
to view your ROR application.
Note: even that your application does not need to use any database, you still have to install and config MySQL ( or another database carrier ) accurately in order for ROR to start a service.
Now, you have everything ready, let start to code.
Coding
ROR follows MVC model with a very strict naming convention, you need to pay a good attention to the names of model, view and controller
Model
To create a ROR model, you can go flickr/app/models , then create a new file named flickr.rb, but there is a better way
rails script/create model flickr
This command will automatically generate all necessary files and folders, such as controller, view, layout, test and set up the configuration as well.
Browse to flickr/app/models/ and open file flickr.rb to add some codes.
We are going to use 3 APIs from Flickr:
flickr.panda.getList : get a list of available Pandas
flickr.panda.getPhotos : get a list of photos under a Panda name
lickr.photos.getInfo: get information of a specific photo.
Noting that , in order to use Flickr APIs, you need to have a API key, to obtain a new key go to
http://www.flickr.com/services/api/keys/apply/
Because Flickr API will return a XML document, so we need to have to import rexml package to handle XML and of course net package to send REST request, you model will start with:
require 'net/http'
require 'rexml/document'
Sample code :
require 'rexml/document'
# key : ce8cc447f982b2f864ba423b8dff3e1a
# secret : 3abb6ef1ec9e1d75
# http://www.flickr.com/services/api/explore/?method=flickr.panda.getList
class Flickr
#@@proxy_addr = 'localhost'
#@@proxy_port = 8000
@@api_key=''
@@uri_list = 'http://api.flickr.com/services/rest/?method=flickr.panda.getList'
@@uri = 'http://api.flickr.com/services/rest/?method=flickr.panda.getPhotos'
@@uri_info = 'http://api.flickr.com/services/rest/?method=flickr.photos.getInfo'
def initialize(key)
@@api_key = key
@@uri ="#{@@uri}&api_key=#{@@api_key}"
@@uri_list ="#{@@uri_list}&api_key=#{@@api_key}"
@@uri_info ="#{@@uri_info}&api_key=#{@@api_key}"
end
def get_list()
#res = Net::HTTP::Proxy(@@proxy_addr, @@proxy_port).get_response(URI.parse(@@uri_list)).body
res = Net::HTTP.get_response(URI.parse(@@uri_list)).body
xml = REXML::Document.new(res)
re="
<ul id="list">"
xml.elements.each('rsp/pandas/panda') do |e|
re = re + "
<li>" +"<a href="\"javascript:getPanda('#{e.text}')\"">"+ e.text+"</a>"+ "</li>
"
end
re = re + "</ul>
"
puts re
return re
end
def get_panda(panda_name,limit=10)
panda_name = panda_name.gsub(' ','+')
uri_temp = "#{@@uri}&panda_name=#{panda_name}&per_page=#{limit}&page=1"
#res= Net::HTTP::Proxy(@@proxy_addr, @@proxy_port).get_response(URI.parse(uri_temp)).body
res= Net::HTTP.get_response(URI.parse(uri_temp)).body
xml = REXML::Document.new(res)
photos =[]
xml.elements.each('rsp/photos/photo') do |e|
photos <<e
end
i=0
re= "
<div id="panda_inside">
<h2>List #{limit} photos of Panda #{panda_name}</h2>
"
re= re + "
<ul id="panda_list">"
while i
if photos[i].attributes["title"]==""
photos[i].attributes["title"]="No Title"
end
re= re + "
<li>" + "<a href="\">" + photos[i].attributes["title"] + "</a></li>
<a href="\">"
i+=1
end
re=re + "</a></ul>
</div>
<a href="\">"
puts re
return re
end</a>
def get_info(id)
uri_temp = "#{@@uri_info}&photo_id=#{id}"
#res= Net::HTTP::Proxy(@@proxy_addr, @@proxy_port).get_response(URI.parse(uri_temp)).body
res= Net::HTTP.get_response(URI.parse(uri_temp)).body
xml = REXML::Document.new(res)
owner=""
title=""
date=""
xml.elements.each('rsp/photo/owner') do |e|
owner = "Author: " + e.attributes["realname"] + ". Location: " + e.attributes["location"]
end
xml.elements.each('rsp/photo/title') do |e|
title = e.text
end
xml.elements.each('rsp/photo') do |e|
date= e.attributes["dateuploaded"]
date = Date.jd(date.to_i)
date=date.strftime("%B %d, %Y")
end
re= "<span id="info">Title: " + title + "
Uploaded date in Julian: " + date.to_s + "
" + owner + "</span>"
return re
end
def get_image(farm,server,id,secret)
src = "'http://farm#{farm}.static.flickr.com/#{server}/#{id}_#{secret}.jpg'"
img = "<img src="#{src}" alt="" />"
info = get_info(id)
re = img + "
" + info
return re
end
end
if your program runs through a proxy, then uncomment
#@@proxy_addr = 'localhost'
#@@proxy_port = 8000
and use the net command with proxy:
#res = Net::HTTP::Proxy(@@proxy_addr, @@proxy_port).get_response(URI.parse(@@uri_list)).body
#res= Net::HTTP::Proxy(@@proxy_addr, @@proxy_port).get_response(URI.parse(uri_temp)).body
#res= Net::HTTP::Proxy(@@proxy_addr, @@proxy_port).get_response(URI.parse(uri_temp)).body
Controllers
rails script/create model flickr
ROR will generate a controller name flickr_controller.rb under the directory flickr/app/controllers/
We will need three actions to handle to different request from the views:
- index
- get_panda
- get_image
Sample code:
end
def get_image
@fl = @@flickr
farm = params[:farm]
server = params[:server]
id=params[:id]
secret = params[:secret]
re = @fl.get_image(farm,server,id,secret)
render :text=>re
end
end
Views
go to flickr/app/views/flickr/, create a file named index.html.erb
<%= javascript_include_tag "flickr.js" %>;
<%= stylesheet_link_tag "flickr.css" %>;
<div id="wraper">
<div id="top"><%= image_tag "rails.png" %><span id="header"> Ruby on Rails</span>
<h1>Flickr Panda Search</h1>
<div><%= render :text=>@fl.get_list() %></div>
</div>
JavaScript<
The javascript will be stored under directory flickr/public/javascripts/
Create a file named flickr.js and use the syntax bellow to include a javacript in the View
<%= javascript_include_tag "flickr.js" %>
function getPanda(name){
//alert(query.value);
try{
asyncRequest = new XMLHttpRequest();
asyncRequest.onreadystatechange = displayPanda;
var url ="http://localhost:3000/flickr/get_panda?panda_name=" + name;
url=url+"&sid="+Math.random();
//alert(url);
asyncRequest.open('GET',url,true);
asyncRequest.send(null);
document.getElementById('panda').innerHTML = '<img id="loader" src="/images/loader.gif" alt="" />';
document.getElementById('img').innerHTML = '';
}
catch(exception){
alert(exception);
}
setCookie("panda",name,180,'/');
}
function displayPanda(){
//alert(query.value);
if(asyncRequest.readyState==4 && asyncRequest.status==200){
var display =asyncRequest.responseText;
document.getElementById('panda').innerHTML=display;
setCookie("panda_list",display,180,'/');
}
}
function getImage(farm,server,id,secret){
try{
asyncRequest = new XMLHttpRequest();
asyncRequest.onreadystatechange = displayImage;
var url ="http://localhost:3000/flickr/get_image?farm="
+ farm + "&server=" + server + "&id=" + id + "&secret=" + secret;
url=url+"&sid="+Math.random();
asyncRequest.open('GET',url,true);
asyncRequest.send(null);
document.getElementById('img').innerHTML = '<img id="loading" src="/images/loading.gif" alt="" />';
}
catch(exception){
alert(exception);
}
}
function displayImage(){
if(asyncRequest.readyState==4 && asyncRequest.status==200){
var display =asyncRequest.responseText;
document.getElementById('img').innerHTML=display;
}
}
CSS
The stylesheet will be stored under directory flickr/public/stylesheets/
Create a file name flickr.css and use the syntax bellow to include a CSS in the View
<%= stylesheet_link_tag "flickr.css" %>
#wraper{width:1003px;min-height:600px;margin:0 auto;border:7px inset #666666; padding:10px 20px 20px 20px;}
#header {font-size:20pt;font-weight:bold;}
#footer{clear:both;}
.middle{float:left;vertical-align:text-top;}
Screen shots:

Download: flick_panda.rar
NDLoc, 28/06/2009
June 28, 2009
Posted in: Web Development
