So, I’m building an educational resource search engine Rails app. This app will display results (e.g. Calculus videos) in a block-type layout meant to leverage Isotope (for cool filtering/sorting transitions and the like).
In addition to querying our database for appropriate Resources, we are also querying Google via their Custom Search Engine API. On top of that, eventually we will want to place some ad blocks into the grid view.
So my question is, how can I combine the @resources returned from querying our database with the JSON results of the Google query and also eventually with ads? I want to do this to make the results view (search.html.erb) as clean as possible. Additionally, I want to be able to sort/filter all of the results. That is, I’d like to be able to merge the ActiveRecord results with the Google query results. This would also allow me to do things like:
(Boxx is the generic class I’m thinking of)
<% @boxxes.each do |boxx| %>
<div class=<%= boxx.type %>>
<h2><%= boxx.title %></h2>
<h3><%= boxx.description %></h3>
...
...
...
</div>
<% end %>
My Resource controller is below. Basically, I want to combine the @resource with the results of a Google query into one enumerable with a common interface and that I can sort according to the sort type specified by the user.
What is the best way to go about this? Should I create a Boxx class at the bottom of the controller and be able to initialize it with either a Resource, google JSON or Ad? Then I could keep a type variable and then be able to sort them all together?
Here’s my Resource controller
require 'will_paginate/array'
class ResourcesController < ApplicationController
def index
@resources = Resource.all
end
def create
# Usability concern here... need to make sure that they are redirected back here once they log in or something
if current_user == nil
flash[:alert] = "You must log in to submit a resource!"
redirect_to resources_path
return
else
params[:resource][:user_id] = current_user.id
end
# Check to see if this resource unique
params[:resource][:link] = Post::URI.clean(params[:resource][:link])
if unique_link?(params[:resource][:link])
@resource = Resource.new(params[:resource])
@resource[:youtubeID] = self.isYoutube(@resource[:link])
@resource.save
else
flash[:alert] = "This resource has already been added!"
end
redirect_to resources_path
end
def vote
value = params[:type] == "up" ? 1 : -1
@resource = Resource.find(params[:id])
@resource.add_or_update_evaluation(:votes, value, current_user)
respond_to do |format|
format.html { redirect_to :back, notice: "Thank you for voting" }
format.json { render :status=>200, :json=>{:success=>true}}
end
end
def isYoutube(youtube_url)
regex = %r{http://www.youtube.com}
if youtube_url[regex]
youtube_url[/^.*((v\/)|(embed\/)|(watch\?))\??v?=?([^\&\?]*).*/]
youtube_id = $5
thumbnail_Link = "http://img.youtube.com/vi/#{youtube_id}/1.jpg"
else
thumbnail_Link = nil
end
thumbnail_Link
end
def unique_link?(url)
Resource.find_by_link(url) == nil
end
def search
@resource = Resource.full_search(params[:q])
# raise params.to_s
@resource = @resource.reject!{|r| !r.media_type.eql? params[:filter][0][:media_type].downcase } if params[:filter] && !params[:filter][0][:media_type].blank?
if params[:filter]
case params[:filter][0][:sort].downcase
when 'newest'
then @resource = @resource.sort_by{|r| r.created_at}
when 'votes'
then @resource = @resource.sort_by!{|r| r.reputation_for(:votes).to_i}.reverse
else
end
end
@resource = @resource.paginate(:page => (params[:page] || 1), :per_page => 15)
end
def google(q, filter)
# Authenticating into Google's API
client = Google::APIClient.new(:key => 'secret', :authorization => nil)
# Discover the Custom Search API
search = client.discovered_api('customsearch')
# Search Google CSE
response = client.execute(
:api_method => search.cse.list,
:parameters => {
'q' => "#{q} #{filter}",
'key' => 'secret',
'cx' => 'secret'
}
)
# Decode the results
results = ActiveSupport::JSON.decode(response.body, {:symbolize_names => true})
# Return an empty array if Google CSE limit has been met.
results["items"] == nil ? [] : results["items"]
end
def make_boxxes(resources, google_results, ads)
end
end
EDIT #1: Wait, can just make a GoogleResult class, then do
@items = @resources | google_results
?
Because I could just make GoogleResult follow the same interface as Resources. But then how do I sort them? Hmmm…
I found what I needed by reading about “Designing Helpers in Ruby on Rails”
http://techspry.com/ruby_and_rails/designing-helpers-in-ruby-on-rails/