rich manalang

aka @rmanalan
« Back to blog
Nov 14
Views

Multi-Model Solr Search in Rails

A few of the JRuby on Rails apps I run use acts_as_solr.  Turns out that the prefered search solutions in Rails today are Thinking Sphinx and Xapian, neither of which I've ever tried before... maybe on my next project.  Anyway, acts_as_solr is pretty useable, however, I've always been stumped with how to perform queries across ActiveRecord models.  Turns out that acts_as_solr has a method called "multi_solr_search" which performs queries across models.  However, it's not very well documented and there's not a whole lot of information in the intertubes.  So, here's how I got my unified site search to work: [code lang="ruby"] # search_controller.rb: default execution searches multiple models. If a scope param is provided # it will search only that model. multi_solr_search can return two two different formats, the object # name and id, or the actual object. If you're query returns a lot of results, you don't want to load # up every single object. The code below loads the object name and id then just loads the object # for the current paginated group. This is using will_paginate. def all if params[:scope] and ["UserProfile", "Idea", "Question", "Group"].include?(params[:scope].classify) scope = params[:scope].classify models = [scope] else scope = "UserProfile" models = [Idea, Question, Group] end # execute solr multi model search based on the scope selected above solr_results = scope.constantize.multi_solr_search(params[:q], :models => models, :results_format => :ids, :limit => 1000).docs.compact @total = solr_results.size solr_results = solr_results.map {|m| r = m.fetch("id").split(":")} per_page = 10 page = params[:page] || 1 # determine array indices that are to be included in the current paginated group first_idx = (page.to_i > 1) ? ((page.to_i - 1) * per_page) : 0 last_idx = (first_idx + per_page.to_i - 1) last_idx = last_idx page, :per_page => per_page) end [/code] I'd love to see if someone could clean this up more. Any takers?