Sort within a Search 2 comments

Posted by robon May 29, 2007

Check out the following screen shot of a queue view from a project I'm working on:

What this is showing is that sorting by a column is preserved across the pages of a result set (the screen shot shows the third page). In other words, if I sort by a column and there is pagination, I want that sort preserved as I flip through the pages of the result. It's just about what you would expect to happen, but often this feature is neglected.

The way I chose to do this was to pass information about the current sort (direction, column) along with the pagination links. (Conversely, I was passing the pagination page information along to the search before I realize that made no sense! :) Anyway, here's the view helper that piggie-backs sort information along with each of the pagination links:

app/helpers/review_helper.rb:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  def review_log_pagination

    search_opts = { :search_str => params[:search_str],
                    :search_field => params[:search_field],
                    :search_method => params[:search_method],
                    :sort_order => @sort_order,
                    :sort_col => params[:sort_col],
                    :old_sort_col => params[:sort_col] }


    string = <<END_OF_STRING

      #{ ( link_to '[previous]', { :page => @review_log_pages.current.previous }.merge(search_opts) ) if @review_log_pages.current.previous }

      #{ pagination_links( @review_log_pages, { :params => search_opts }, { :window_size => 10 } ) }

      #{ ( link_to '[next]', { :page => @review_log_pages.current.next }.merge(search_opts) ) if @review_log_pages.current.next }

END_OF_STRING

  end

There are two views that use this helper. If it was to be used anywhere else, I could make it an application level helper but for now, this works. I believe there are also JavaScript/CSS column sorting solutions, but some of the sorting logic that's involved was a lot easier in Ruby.

I'm open to any ideas about how to make this smoother. Even though it works pretty well, there are references to a lot of outerscope variables which could make changes down the line more work.

As an aside, here's how Hash#merge works:

orsini@MacOrsini:~
$ irb
irb(main):001:0> { :one => 1, :two => 2 }
=> {:one=>1, :two=>2}
irb(main):002:0> third = { :three => 3 }
=> {:three=>3}
irb(main):003:0> { :one => 1, :two => 2 }.merge(third)
=> {:one=>1, :two=>2, :three=>3}

Comments

Leave a response

  1. Dan KubbMay 29, 2007 @ 11:52 PM

    I do something similar to you, except I think the approach is a bit simpler. It only works if the search and pagination parameters are specified in the query string.. which IMHO is the way to go if you want your search results bookmarkable.

    Basically I have helper methods for the previous/next pagination links, and for the sort column links. They merge a hash with new values into whatever request.query_string returns.

    The beauty of this system is that if I were to add new parameters to the query string, all my link helper methods would still continue to work.

  2. Jamey CribbsMay 30, 2007 @ 07:03 AM

    Hey, Rob.

    I have something similar in one of my current projects. The way I do it is I store a hash in the user’s session that holds the last used sort and filtering criteria. Then, in the controller’s list method, I repopulate my sort and filter variables from the session before I do any #finds.

    I have it working pretty well in both ajax and degraded mode. I stole a good part of the idea from an article I read about ajax sorting and layered more functionality on top.

    I need to DRY it up a little and possibly look at turning it into a plugin.

    Your initial premise is correct. It is important to preserve sorting and filtering across pagination in order to give the user the feel that they are using a desktop app. A lot of web apps ignore this.

    Thanks for this post.