« Safari now supports LiveGrid & AjaxEngine | Main | Simplifying XML navigation in Ruby »

November 06, 2005

Openrico Yahoo Example in Rails

When I converted the yahoo demo to Ruby on Rails, the resulting ruby code was quite simple - actually downright trivial. Part of this simplification is due to the way Ruby allows the developer to think about the solution in its simplest most direct form. 

The original java code used beans that were built from the xml results.  I really liked the way you could navigate from bean to bean through simple properties.  However, I did not really want to define all the beans and mappings.  Call me lazy.  So, I decided to do a simple wrapper around the XML root from REXML so that I could access the nested xml elements/objects as simple named properties.  This allowed me to do the following implementation for the yahoo demo of the LiveGrid.  It has 3 ajax calls for the web, image, and video search.

@@YAHOO_HOST =  "api.search.yahoo.com";  

after_filter :mark_ajax, :only => [:ajax_yahoo_web_search,
                                   :ajax_yahoo_image_search,
                                   :ajax_yahoo_video_search];   

def mark_ajax
   @response.headers["content-type"] = 'text/xml'; 
end


def ajax_yahoo_web_search
@yahoo = _get_object_response(@@YAHOO_HOST,      
                               _yahoo_path("/WebSearchService/V1/webSearch");
render :action => :ajax_yahoo_web_mock unless !@yahoo.nil?;   
end
def ajax_yahoo_image_search
   @yahoo = _get_object_response(@@YAHOO_HOST,
                                 _yahoo_path("/ImageSearchService/V1/imageSearch"));
   render :action => :ajax_yahoo_image_mock unless !@yahoo.nil?;      
end
def ajax_yahoo_video_search      
   @yahoo = _get_object_response(@@YAHOO_HOST,
                                 _yahoo_path("/VideoSearchService/V1/videoSearch"));      
   render :action => :ajax_yahoo_video_mock unless !@yahoo.nil?; 
end

private

def _yahoo_path(base)   
"#{base}?query=#{@params[:query]}&start=#{@params[:offset].to_i+1}&results=#{@params[:page_size]}&appid=#{@@yahoo_app_id}"
end

def _get_object_response(host, path, sanitize)
   response = Net::HTTP.get_response(host, path);

   if (response.message != "OK") then
      flash.now[:notice] = "Could not access server";
      return nil;  #let the caller generate mock data
   end;
   SanitizedXMLObject.new(REXML::Document.new(response.body).root)
end

We use a The SanitizedXMLObject that extends the XML wrapper class and automatically textifies (so we can nest it into our page cleanly) all content.  This takes the root of the REXML::Document object and makes it simpler to work with.

This is all the code needed to provide the 3 yahoo search actions that query the Yahoo search API and prepares the results ready for the rhtml templates. 

Now, the template is very simple and clean and uses the @yahoo as if it is a network of objects that can be traversed as either a property or through an "each" method.

 <ajax-response>
  <response type="object" id="webSearchResultsGrid_updater">
    <rows update_ui="true" >
      <% i = 0;
        @yahoo.each(:Result) do |result| %>
        <tr>
            <td>
               <span class="webSearchIndex"><%=@params[:offset].to_i + (i+=1)%>.</span>
            </td>
            <td>
               <a class="webSearchTitle" href="<%=result.ClickUrl%>">
                  <%=result.Title%>
               </a>
                <div class="yahooSearchItemSummary">
                   <%=result.Summary == nil ? "" : result.Summary.to_s[0..200]%>
                </div>
                <div class="webSearchUrl"><%=result.Url%> -
                   <span class="webSearchFileFormat">
                      <%=result.MimeType%>
                   </span>
                </div>
            </td>
        </tr>
    <% end %>
    </rows>
  </response>
    <response type="element" id="webResultStats">
      <span>&#160;of about <%= @yahoo.totalResultsAvailable%> for <%=@params[:query]%></span>
    </response>
    <response type="object" id="configureWebSearchRows">
      <numResults><%=[@yahoo.totalResultsAvailable.to_i, 1000].min%></numResults>
    </response>

</ajax-response>

This seems to be pretty straight forward (as it should be).

The initial page has a bit more content and javascript code to initiate the LiveGrid with different types of search results.  I will not go over it at this point, but it is available here for download.

I will talk later about the wrapper class for the xml.

Comments

The comments to this entry are closed.