The Pitfalls of Ultrasphinx and Ultraminx

Recently, we had a Merb project that we needed to add search to. Now, since Merb doesn’t use plugins the same way Ruby does, I decided to look for a nice easy gem to make life easier. At the time, I found ultraminx. Ultraminx was basically ultrasphinx made into a gem with no docs. Things were good, except that it broke when I decided to upgrade to the latest version of Merb.

The problem that I found is that when we did the upgrade, Ultraminx refused to work. In fact, I was rather disturbed that the repository hasn’t been touched in a while. Therefore, I decided to look at Ultrasphinx again. I found that on GitHub that it was forked numerous times by different developers, and I eventually used Jamie’s code. However, I had to hack it as well.

Straight from the github

However, even that is rather old. I’m tempted to do what 10 other people have done before me and fork the ultrasphinx code and to see what happens when I pull from these other repos. Of course, I haven’t taken the plunge and used DataMapper or Sequel yet, so I’m going to wait until MerbCamp to see what happens when I hack on this.

Yes, I said I’m going to MerbCamp.

will_paginate and Ajax pagination

One thing that I’ve been using a lot is will_paginate and it’s derivatives, such as merb_paginate, ultraminx and ultrasphinx. One problem that I noticed with merb_paginate was that it didn’t want to use the restful paths in the merb app that I was using. This was rather annoying, since I was trying to make my merb app almost entirely restful, except for the home controller. So, instead of using paginator, I decided that I wanted to add ajax pagination.

The first step that needs to be done is to create a create and delete js view. This is extremely basic. I have some code that does this in one of my github repositories. Namely, the sparty_server code.

In the controller, uncomment this line as usual. We are going to be sending back json:

 provides :xml, :yaml, :js

Then create the following *.js.erb files:

index.js.erb

var events = "";
<%= partial "widgets", :with => @widgets %>
<%= partial "shared/paginate", :items => @widgets %>
$jQ("#main_eventlist").empty();
$jQ("#main_eventlist").append(events);
$jQ(".pagination").empty();
$jQ(".pagination").append(navigation);

Note that you should really make this so that it uses your jQuery variable. Here, we’re not using noConflict. noConflict should almost always be used, since you most likely will be using a non-jQuery item with your software. We also created two partials, namely one that just lists the lists. This could be used for anything that will update inside a div. The other thing that we created is a pagination partial, which is just a string definition.

This is pretty obvious. This just uses the methods present in all will_paginate derived objects to determine which page is present. One thing that we found is that we don’t always have access to all the methods and attributes, which is why it looks rather odd.

Here’s the javascript code that does the pagination:

var prevPaginate = function(id)
{
  items = id.split('_')[1];
  current_page = id.split('_')[2];
  next_page = parseInt(current_page) - 1;
  next_page_key = "#page_" + next_page;
  uri = parseMerbUri(window.location.href);
  good_uri = window.location.href.split("#")[0];
  next_page_key = good_uri + next_page_key;
  hist.add(next_page_key);

  query_string = uri + "?page=" + next_page;
  if(next_page > 0)
  {
    jQuery.get(query_string, function(data){eval(data);});
    return false;
  }
}

var nextPaginate = function(id)
{
  items = id.split('_')[1];
  current_page = id.split('_')[2];
  next_page = parseInt(current_page) + 1;
  uri = parseMerbUri(window.location.href);
  good_uri = window.location.href.split("#")[0];
  next_page_key = good_uri + "#page_" + current_page;
  hist.add(next_page_key);

  query_string = uri + "?page=" + next_page;
  jQuery.get(query_string, function(data){eval(data);});
  return false;
}

Of course, we have a method that parses the URI so that we are going to the right resource. This is important for nested resources to do this, since we want to display the correct results. We also use the Nitobi history in this case because we want the back button to use the pagination, and not go back to the previous page in the history.

I’m going to make this more generic in the next couple of weeks and post the code to the blog, however this should be rather trivial for anyone to do once they know how will_paginate works and how to use the json data that it sends back.