Here is where I post things

Laziness. Impatience. Hubris.

Building a Responsive Image Search in an Hour With Sinatra

So I was gearing up to build something to work with APIs and practice Sinatra, but then I realized I was going to build a food app again. I decided I needed an influx of fresh ideas, so yesterday I asked my non-technical friend, Jackie, what I should build. She had two ideas, one of which sounded insanely difficult and the other sounded maybe easy enough to get done in time. Jackie is getting married this Spring and simply wanted a way to search for images, browse the results, and pin the ones that caught her eye to Pinterest, in effect building a wedding mood board.

Sinatra makes setting up web apps pretty simple and image searching is a pretty standard request, so I decided to give it a go.

Finding a search solution

First I checked out the Google Search API. It was a bit confusing and I wasn’t completely sure what features were available for web search vs custom site search or which features were free and which required a paid account. So, I turned to the comforting world of Ruby Gems and looked for a good wrapper. I found one called Google Search (aptly) that hadn’t been updated in a couple years, but I didn’t see any other options, so I gave it a try.

require 'google-search'
g = Google::Search::Image.new

The gem didn’t have too much documentation, so I played with it in irb a bit, and it seemed pretty straightforward. After requiring the gem and instantiating the class, I got an object I could try different methods on.

#=> <Google::Search::Image:0x00000102153990 @color=nil, @image_size=nil, @image_type=nil, @file_type=nil, @safety_level=nil, @type=:image, @version=1.0, @offset=0, @size=:large, @language=:en, @query=nil, @api_key=:notsupplied, @options={}>

Seeing that there was a query attribute, I figured I could shove something in there:

g.query = "kittens"

And running g.methods let me know that my object behaves like an enumerable.

g.each { |i| puts i.uri } #=> so many kittens, you have no idea

At this point, I felt comfortable that the google-search gem would at least meet my basic needs for image search functionality. Time to build!

Setting up Sinatra

I put together a basic Sinatra scaffolding, set up bundler and rspec. Once I get that running, I start thinking about my endpoints and how the search will work. I set up some routes and make sure the urls are working as expected when I rackup.

module JackieImageSearch
  class App < Sinatra::Base

    get '/' do

      erb :"index.html"
    end

    get '/search' do
      @term = params[:query]

      @search_results = Google::Search::Image.new
      @search_results.query = @term

      erb :"show_results.html"
    end

  end
end

Once the urls are set up, it takes me a few minutes of fiddling with it to get the controller and form working together properly.

<form action="/search" method="get">
  <label for="query">Search</label>
  <input type="text" id="query" name="query" />
  <input type="submit" value="search">
</form>

Once I have my get request actually passing it’s params to my results page, I’m ready to build out the view and my logic for displaying the results. I start with a simple list of image URLs, then after I confirm that is working, I built out the actual image tags as list items. And at this point, I realize I’m basically done! How awesome is it that you can build a working search in 45 minutes using open source tools?

Making it pretty

So, now I need to see if I can make it pretty. Or at least prettier. A long list of giant images is not so pleasant to scroll through. My initial thought is to just style the images to scale down to some reasonable size and display them in simple fixed-height/width rows. But I really hate the idea of a fixed width for this site, so I do a Google search for “responsive image grid” with pretty low expectations. I find a pure CSS solution that looks simple enough, copy/paste and adapt my erb to give it a try.

<section id="photos">
<% @search_results.each do |result| %>
    <img src="<%= result.uri %>" />
<% end %>
</section>

To my surprise, it works right away.

Results for green vase

Seamless Responsive Image Grid: http://css-tricks.com/seamless-responsive-photo-grid/

Adding the Pin buttons I knew would be fairly trivial because social apps like Pinterest always provide little JavaScript buttons for site admins to embed. I visit the Pinterest developer portal and snatch the “appear on hover” button. It only requires including a JS file, so I do so and test out the functionality. It works with the exception of denying my “localhost” source location.

So, could I improve the code? Yes. Could it use more style? Absolutely. But I’m pretty pleased that we live in a world where tools are readily available to build a working search with a remarkably Pinterest-like interface in under an hour.

Check it out on GitHub: https://github.com/NegaMorgan/jackie-image-search