Rolling your own pagination with will_paginate

2008-09-16 20:00:00 -0400


So I’ve been working on some decent paging of time entries for Tempo’s reporting interface. I would have loved to have just ran with the fantastic will_paginate plugin, but we don’t generate what you see on the reporting screen in Tempo via a simple Rails find call on the Entry model. Instead we have a class that builds the appropriate SQL according to the various report specs and then runs it via find_by_sql. Actually, it does quite a bit more than that, but I don’t want to get off topic.

Anyway, this meant we couldn’t simply expect will_paginate to know what kind of SQL it should generate, because the standard options on find wouldn’t be enough. But the plugin was really quite well-designed for extensibility, and that made it a snap to get our own paging going on:


class ReportContext
...
# the list of entries to display based on context
def entries
self.prepare # make sure the SQL for this report is already built and sanitized

@offset = DEFAULT_OFFSET if @offset.blank? or @offset < 1
@limit = DEFAULT_LIMIT if @limit.blank? or @limit < 1

@entries = WillPaginate::Collection.create(@offset, @limit) do |pager|
# must use a duplicate or original sql is modified (this can get pretty vexing)
sql = Entry.send(:add_limit!, @sql.dup, :limit => pager.per_page, :offset => pager.offset)
result = Entry.find_by_sql([sql])
pager.replace(result)

unless pager.total_entries
# the pager didn't manage to guess the total count, do it manually
pager.total_entries = self.count # run the count sql for this report
end
end
end

Now that our @context.entries method is returning a will_paginate collection, we can pass it to the view helpers, and voila:


- paginated_section @context.entries, :params => { :action => :index } do
#data
%table#entry-list.tabular-list
%tbody
%tr#entry-header.header
%th{:style => "text-align: center;"}= sortable_column('Hours', 'hours')
%th= sortable_column('Date', 'occurred_on')
%th= sortable_column('Person', 'user_name')
%th= sortable_column('Project', 'project_name')
%th Tags
%th Description
%th= sortable_column('Created', 'created_at')
%th= sortable_column('Updated', 'updated_at')
%th.actions.noprint
- @context.entries.each_with_index do |entry, i|
= render :partial => 'entries/entry_tr', :locals => {:entry => entry}

Note how we’re passing the :action parameter into the :params option of the helper. This gets passed to the link generators that create the actual pagination links. Because this view is generated in a partial, any number of methods could have displayed it from differing XHR calls to different REST urls (entries/filter, entries/data, etc), and we have to make sure that any pagination links would bounce off the index action. By default the pagination will link to the URL of the current request.

Oh, right, so that sortable_column business? We’re finally adding this oft-requested feature into an upcoming update to Tempo.


We're Hiring

2008-09-08 20:00:00 -0400


We just posted this to Craig’s List, but I figure we might as well get it up here, too. We’re looking to hire a web application developer. Our work load is expanding pretty rapidly and it’s time to bring on someone new to help us grow. If you’re a regular reader of this blog, you have a pretty good idea of the work that we do and how we roll. We’d really appreciate you forwarding this post on to anybody you know who might be a good fit.

Zetetic is a talented software development consultancy looking for a new teammate. We’re searching for a full-time developer to help us build and maintain client systems and our own applications (our newest product is Tempo, a time-tracking service).

The person we’re looking for has a couple of years experience and work to show off in a personal or professional portfolio. We need a developer with a passion for solving interesting problems.

Basic requirements:

  • A foundation in SQL and relational databases (such as: PostgreSQL, Oracle, SQL Server, MySQL)
  • Having either built or contributed to a Ruby on Rails or .NET application (with a desire to pick up Ruby)
  • An understanding of object-oriented programming
  • Working knowledge of CSS and Javascript
  • Great verbal and Internet communication skills
  • Self-motivation and an unflappably positive attitude
  • Comfortable working with command line interfaces

To apply send us your resume and a brief cover letter explaining your interest and relevant experience.

E-mail us at support@zetetic.net.


ruby-ldap gem for Windows

2008-09-08 20:00:00 -0400


Ruby/LDAP is a useful ruby library that allows you to connect to and manipulate LDAP directories like OpenLDAP and Active Directory. Unfortunately

  • the library isn’t distributed as a gem; and
  • depends on native LDAP libraries for its operation

This puts it out of reach for many ruby developers deploying to a Windows environment without an installed C compiler. In the past I’ve leaned on a few good Samaritans that posted pre-compiled versions, but unfortunately most of these have either been taken down or are really old.

So, in desperate need of an install on a new windows VM I just built it from source. If you trust our binaries you can download the gem-ified ruby-ldap build based on the latest 0.9.7 release and compiled using Visual Studio 2008.


unzip ldap-0.9.7-mswin32.gem.zip
gem install ldap-0.9.7-mswin32.gem

I’ve tested this on a few boxes, though your mileage may vary.

Zetetic is the creator of the super-flexible Tempo Time Tracking system.

Reading on CLI's and GUI Interaction

2008-08-26 20:00:00 -0400


As I’ve written here before, we’re really big fans of the efficiency and simplicity of command lines here at Zetetic. We actively use them at points in the PingMe and Tempo are considering expanding our use of them, in particular to include Graphical Keyboard User Interfaces.

So, some interesting reading:


Deep Thought

2008-08-26 20:00:00 -0400


ANYTHING is possible in PL/SQL.