If you’ve been following our blog you may have noticed that we’re using Solr and ActsAsSolr plugin for our searching.
Getting started with acts_as_solr
acts_as_solr for development and production in one Tomcat instance
Optimizing Solr and Rails – Index in the background
Unfortunately being Java, Solr is a bit of a memory hog. We’ve attempted all sorts of optimizations, but we’re going to take a leap and switch to Sphinx. Sphinx is a free open-source SQL full-text search engine.
First step is to get Sphinx itself installed. For that have a look at Rob’s post:
http://www.notch8.com/articles/2007/10/15/sphinx-and-ultrasphinx-and-eye-on-search
Ultrasphinx works pretty much out of the box with will_paginate; however, a lot of our work is currently compatible with paginating_find. So to keep rails memory footprint down by using one plugin we’re sticking with paginating_find. Unfortunately Ultrasphinx doesn’t work out of the box with paginating_find, so time for a little hacking…
Install paginating_find plugin:
piston import http://svn.cardboardrocket.com/paginating_find/paginating_find vendor/plugins/paginating_find
More information on paginating_find
Install ultrasphinx plugin:
piston import http://fauna.rubyforge.org/svn/ultrasphinx/trunk/ vendor/plugins/ultrasphinx
More information on Ultrasphinx
Now for hacking Ultrasphinx plugin to work with Paginating Find plugin. Piston is great for managing plugins; however, it can easily get confused if you’ve hacked a plugin directly. The solution: use a method called “Evil Twin” as mentioned on the Err the Blog: Evil Twin Plugin
Create a directory for the hack:
mkdir vendor/plugins/ultrasphinx_hacks
touch vendor/plugins/ultrasphinx_hacks/init.rb
Now edit the vendor/plugins/ultrasphinx_hacks/init.rb file with the hacks for paginating_find:
# Hack to allow Ultrasphinx to work with pagination_find
Ultrasphinx::Search.module_eval do
def first_page
1
end
def last_page
self.page_count
end
def previous_page?
previous_page ? true : false
end
def next_page?
next_page ? true : false
end
end
Now for adding a method to your controller for the search:
app/controllers/posts_controller.rb
def search
@query = h(params[:query])
begin
@posts = Ultrasphinx::Search.new(:query => @query,
:class_names => ‘Post’,
:page => params[:page] || 1, :per_page => 20)
@ posts.run
rescue RuntimeError
flash[:warning] = ‘Search is currently disabled. Please try again in a few hours.’
rescue NoMethodError
flash[:notice] = ‘No records found for this search’
end
render :action => ‘list’
end
app/views/posts/list.html.erb
-
< % @posts.each do |cog| %>
- < %= posts.name %>
< % end %>
< %= paginating_links(@posts) %>
Paginating End Result
Bonus : will_paginate styled links
Unfortunately paginating_find doesn’t automatically have the “style” that will_paginate automatically comes with. So to fix that just add a little css for the style and a partial for the pervious and next buttons.
.pagination{
padding: 2px;
}
.pagination a, .pagination a:visited{
padding: 0 5px;
border: 1px solid #9aafe5;
text-decoration: none;
color: #2e6ab1;
}
.pagination a:hover, .pagination a:active{
border: 1px solid #2b66a5;
color: #000;
}
.pagination .currentpage{
font-weight: bold;
padding: 0 5px;
border: 1px solid navy;
background-color: #2e6ab1;
color: #FFF;
}
.pagination .disablepage{
padding: 0 5px;
border: 1px solid #929292;
color: #929292;
display: inline;
}
And now for the partial:
app/views/shared/_paginate.html.erb
< % if (collection.is_a?(PagingEnumerator) || collection.is_a?(Ultrasphinx::Search)) && (collection.page_count != collection.first_page) -%>
< %= link_to '« previous', url_for(:overwrite_params => { :page => collection.previous_page }) %>
< % else -%>
< % end -%>
< %= paginating_links(collection, {:window_size => 4, :always_show_anchors => true, :params => {:query=> params[:query]}} ) %>
< % if collection.next_page? -%>
< %= link_to 'next »', url_for(:overwrite_params => { :page => collection.next_page }) %>
< % else -%>
< % end -%>
< % end -%>
So in your code replace the code paginating_links call with a render partial:
# OLD VERSION
< %= paginating_links(@posts) %>
# NEW VERSION
< %= render :partial => ‘shared/paginate’, :locals => {:collection => @posts} %>
Styled Paginating End Result
Resources:
ErrTheBlog: Evil Twin Plugin
Will Paginate Plugin
Paginating Find Plugin
Ultrasphinx
Sphinx


Recent Comments