Integrating Flickr into your rails website

Anton Jenkins | April 06, 2009

In this post I’m going to show you how I created the little Flickr stream you can see running down the right hand edge of this site.

Step 1: Get a Flickr API key

Visit this page and follow the instructions to get a key and write it down somewhere safe. Of course you are going to need a Flickr account to do this as well!

Step 2: Install the flickr_fu gem

This is the library that makes all the magic happen. Install the gem on your machine:

1
sudo gem install flickr-fu

Notice that’s a hyphen between ‘flickr’ and ‘fu’, not an underscore. And remember that you’ll need to install this gem on your production server as well, so make a note to do that.

Step 3: Tell your rails app to include the flickr_fu library

Just a quick visit to environment.rb to pull it in:

1
2
3
# config/environment.rb

require 'flickr_fu'

Underscore used this time. Very confusing!

Step 4: Configure the gem using a flickr.yml file

The best place to store this is in your config directory along with all your other config settings. Get that piece of paper handy that you wrote down your API key on because you will need it now:

1
2
3
4
5
# config/flickr.yml

key: "<paste your key in here>"
secret: "<paste your secret in here>"
token_cache: "token_cache.yml"

You won’t need the API key any more so you can eat that piece of paper.

Step 5: Have a play!

Right. Time to mess with it! What we are going to do now is fire up the rails console and retrieve some of your images. However the flickr APIs need to know your Flickr ID. For this we will use a website called idGettr

What you do is paste in the URL for your Flickr photostream and it spits out your Flickr ID which we can then use with the APIs. So for me I typed in http://www.flickr.com/photos/antonjenkins/ and it returned an ID of 12864272@N02.

Write this down somewhere, memorise it and then eat the piece of paper.

So lets have a play in the rails console:

1
2
3
4
# ./script/console

>> flickr = Flickr.new(File.join(RAILS_ROOT, 'config', 'flickr.yml'))
=> #<Flickr::Base:0x395d514 @token_cache="token_cache.yml", @api_secret="oooh, that's a secret!", @api_key="I could tell you but I'd have to kill you">

What we’ve done there is pointed flickr_fu to our little flickr.yml file and it’s given us back a connection to Flickr. So lets use it (and that Flickr ID we looked up a minute ago)....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>> photos = flickr.photos.search(:user_id => "12864272@N02")

# Boom! Loads of output!

>> photos.count
=> 90

# I seem to have an array of photos. Lets look at one...

>> photos[1].title
=> "Quack!"
>> photos[1].url
=> "http://farm4.static.flickr.com/3104/3303703736_ba4bea1dc5.jpg"

# Jackpot!

So we’re very happy now – we’re using ruby to talk to Flickr! What we need to do now is get this on to our website.

Step 6: Writing a flickr helper

It’s a good idea to separate out functionality like this into helpers and partials, rather than weave it directly into your existing code. So we’re going to create a flickr_helper.rb in the app/helpers directory like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# app/helpers/flickr_helper.rb

module FlickrHelper  
  def user_photos(user_id, photo_count = 12)
    flickr = Flickr.new(File.join(RAILS_ROOT, 'config', 'flickr.yml'))
    flickr.photos.search(:user_id => user_id).values_at(0..(photo_count - 1))
  end
  
  def render_flickr_sidebar_widget(user_id, photo_count = 12, columns = 2)
    begin
      photos = user_photos(user_id, photo_count).in_groups_of(2)
      render :partial => '/flickr/sidebar_widget', :locals => { :photos => photos }
    rescue Exception
      render :partial => '/flickr/unavailable'
    end
  end
end

The method which we will be calling from our view to display our flickr photos is:

1
render_flickr_sidebar_widget(user_id, photo_count = 12, columns = 2)

This method will prepare an array of photos and pass them to a partial (which we’ll get to in a minute). You may have noticed the call to in_groups_of which is quite interesting:

1
photos = user_photos(user_id, photo_count).in_groups_of(2)

Because we want two columns of photos in our little sidebar we need to group the array of photos. This is where in_groups_of comes into play. Let’s see how it works on the rails console:

1
2
3
4
5
6
7
8
>> Array(1..10).in_groups_of(4)
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, nil, nil]]

# Notice how it pads out the last array with nils

# We want to do group our flickr photos into groups of 2, one for each column
>> Array(1..6).in_groups_of(2)
=> [[1, 2], [3, 4], [5, 6]]

So our photos will group like so:

This grouped array gets passed to the flickr/sidebar_widget partial. Let’s take a look at that now:

1
2
3
4
5
6
7
8
9
10
11
12
13
# app/views/flickr/_sidebar_widget.html.erb

<div class="flickr">
  <ul>
    <% photos.each do |row| -%>
      <li>
        <% row.each do |p| %>
          <%= link_to(image_tag(p.url(:square), :class => 'flickr_photo', :title => p.title, :border => 0, :size => '75x75'), p.url_photopage) %>
        <% end %>
      </li>
    <% end -%>
  </ul>
</div>

I’m then styling this with the following CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.flickr ul
{
        list-style-type: none;
        margin: 0;
        padding: 0;
}
.flickr ul li 
{
        border-bottom: 0;
        margin: 0;
        padding: 0;
}

.flickr_photo
{
        width: 75px;
        height: 75px;
        padding: 12px 10px 32px 13px;
        margin: 0;
        background: #fff url(../images/pixellated/polaroid.jpg) no-repeat;
}

Each flickr thumbnail is placed on top of a little fake polaroid image I knocked up:

You may have also noticed a call in our flickr helper to an unavailable partial if there was an exception whilst trying to speak to flickr:

1
2
3
rescue Exception
  render :partial => '/flickr/unavailable'
end

I’m leaving that partial blank so if flickr is down it just doesn’t render anything. But if you want you can display something else instead of the flickr output then place it in the _unavailable.html.erb partial.

Step 7: Call the helper in your application.html.erb layout template

Just a simple call to…

1
<%= render_flickr_sidebar_widget('12864272@N02') %>

Of course you’ll put your own flickr ID in there instead of mine. Unless you really like my photos?! ;o)

Are we done yet?

Ah. Not quite! You may have noticed something about this when you started testing it…... it’s slow as hell! Every single page render now has to wait for a round trip to flickr. Not cool!

Step 8: Fragment caching to the rescue!

This is a perfect candidate for fragment caching. The flickr photos aren’t going to be changing too often so we can cache them and expire them when we know they have changed.

So we’re going to surround the call to the flickr helper in a fragment cache block:

1
2
3
<% cache ("flickr_sidebar") do %>
  <%= render_flickr_sidebar_widget('12864272@N02') %>
<% end %>

Remember this won’t speed up your renders on your development server as caching is disabled by default in development, but on production it will fly. It won’t cache the images (and why would you want to as flickr is built to serve images?) but it will cache the actual HTML code which required the costly API calls to flickr in order to generate.

Now we need some code to expire this cache when you’ve added some photos to flickr and you want to update the photos on the website. In fact, it would be really cool if you could expire this cache using capistrano, so you wouldn’t even need to ssh into your server to do this. For this I refer you to my previous post on expiring page and fragment caches using capistrano.

comments powered by Disqus