ClickAider
You are currently browsing the Bogle’s Blog weblog archives.

Mobile World Cup scores using Berry411 and Google

You can find the latest World cup scores on Berry411 by typing “wc:” or (for example) “wc: brazil”, courtesy of Google Mobile.

Preview the World Cup Results

Easy FastCGI for Ruby on Rails

Using FastCGI with Rails is more complex than it ought to be, but a simple script can make it nearly trivial.

The Lighttpd launcher script is a drop-in alternative to script/server which uses Lighttpd and FastCGI rather than web-brick. Just launch it and go, or pass the --daemon switch to run as a daemon. Lighttpd is generally recognized as one of the highest performing web servers to use wtih Rails. (I ran yum install lighttpd and yum install lighttpd-fastcgi to install the necessary prerequisites on Fedora.)

My only nit is that there should be an option to update the global lighttpd config in etc and restart the main lighttpd service rather than creating a private server; I’m currently working on changes to add this functionality and will share it when ready.

What about running FastCGI with Rails on Apache 2? This appears to be a bad idea in general. James Duncan Davidson reports on consistent problems under load with zombie Rails processes. The post links to a number of different posts from around the web that confirm and diagnose the problem, and suggests alternative configurations including Lighttpd rather than using FastCGI in Apache directly.

My own experience seems to confirm this; my system became unusable under the weight of zombie processes (with a load of greater than 30 and incredible amounts of swapping.) I’ve switched instead to a configuration in which Apache acts a reverse proxy to a Lighttpd/FastCGI/Rails server.

Browse and Share Berry411 Mobile Search Plugins

The Berry411 Plugins page is a new feature of the Berry411 service. It provides a categorized directory of all Berry411 search plugins, including previews of the results from each plugin. You can also add new plugins and share them with the Berry411 community.

Some of the best ideas for plugins, like the recently flight tracking plugin, come from users, so this is an easy do-it-yourself way for any user to add a plugin. (A plugin can point to the results of search form, or simply be a convenient name for a page to save users to trouble of typing a long URL.)

Personalization features like Berry Plugins will now be much easier for me to implement, now that I have rewritten the core of the Berry411 backend in Ruby on Rails. It’s possible there will be a few bumps in the road with this significant transition, so please share with me any problems you might encounter as well as suggestions for improvement.

And please do create some plugins!

Google Spreadsheet Impressions

I have tried the beta of Google Spreadsheets and am generally impressed. But if you’re a spreadsheet author rather than just a consumer of spreadsheet data, don’t throw away your copy of Excel quite yet– there are still compelling advantages that only a rich client can provide.

What we really want is a hybrid of rich client and web based spreadsheet models that provides both reach and richess. Regardless of how they were created, documents should be accessible collaboratively by anyone with a web browser, and for many users the browser will be all they need. But document authors who care about a rich, highly responsive authoring experience should have the option of installing a native client to provide those features, with technology such as .Net, Java, or Flash possibly serving to reduce the installation issues traditionally associated with rich clients.

On the pro side, Google Spreadsheets definitely the nicest of the online spreadsheets I have tried. Cell selection and editing and keyboard shortcuts work for the most part exactly as you’d expect, though there are few omissions (e.g. HOME and END do not work.) You get the expected benefits of web based applications– no install, the ability to access your data from any computer, and the ability to share and collaborate with other users on the web. Two users can even edit the same sheet at the same time. Multi-level undo is supported, even across different browser sessions. You can import Excel documents from your desktop, including ones with multiple sheets.

On the con side, features that experienced spreadsheet users rely on aren’t present and some of these features will be difficult to add within the constraints of a web based application. Scrolling is a bit sluggish and has a “ripple” effect for large spreadsheets. There is no autofill, autosum, filtering, or drag-and-drop moving of blocks of data. There is no conditional formatting, charting functionality, or pivot tables.

Who gets to the ideal hybrid of web and rich client access is a difficult call. Can Microsoft produce or partner with a web spreadsheet service and adapt Excel to save documents with high fidelity on the web? Will Google or Sun adapt OpenOffice or other technology to work with its spreadsheet? Or will the universal browser platform become rich enough to do highly responsive spreadsheet authoring, via the addition of a spreadsheet form element?

Swaptree: Netflix for free swaps

I was just chatting with Jason Warner at Starbucks and he told me about a very cool, early stage startup called Swaptree, located in Boston. I’m looking forward to trying it out when it leaves closed beta.

Business 2.0 called Swaptree the eBay of swap, but to me they look more like the Netflix of swap.

What they’ve done is taken all of the hassle out of multi-way swaps of old books, cd, dvds, and video games, in the same way that Netflix has simplified video rentals.

They have a database of millions of such items, so simply by punching in a UPC or ISBN number they can complete the description with album art, description, and shipping cost. They allow you to print postage and shipping labels right from the web site, and they have ready-to-go mailers (a la Netflix) for different sized items.

The site has algorithms for facilitating multi-way swaps, so you don’t have to find someone who wants to do a direct swap. Presumably they’ll have a reputation system to deter cheaters.

Swaptree charges no fees for swaps; they make money from advertising based on information about who is swapping what.

I understand they are looking with some urgency for a skilled SQL Server DBA, so if you meet that description and are interested let me know and I’ll forward your resume on.

paginate_by_sql for Rails: a database independent approach

Like many people, I needed a paginate_by_sql for Rails-- a variant of paginate that would allow pagination for arbitrary SQL; something that would work with Oracle and scale to large result sets. This functionality, surprisingly enough, isn't part of the built in Rails framework.

I found several existing solutions on the web, but they either were either hard-coded for Mysql SQL syntax or inefficient, fetching the entire result set then throwing away rows outside the window.

Fortunately all of the needed machinery to do a database independent paginate_by_sql is available underneath the covers in ActiveRecord. The following code adds a paginate_by_sql call to ActionController::Base and a find_by_sql_with_limit method to ActiveRecord::Base; just add it to the end of application.rb.

[Update: The code below now includes improvements from Laurel's blog. It allows the sql to be passed in with an argument list by using sanitize_sql, and it allows an optional :count argument to specify (as an optimization) an integer or query to use for computing the total count.]

module ActiveRecord
    class Base
        def self.find_by_sql_with_limit(sql, offset, limit)
            sql = sanitize_sql(sql)
            add_limit!(sql, {:limit => limit, :offset => offset})
            find_by_sql(sql)
        end

        def self.count_by_sql_wrapping_select_query(sql)
            sql = sanitize_sql(sql)
            count_by_sql("select count(*) from (#{sql}) as my_table")
        end
   end
end

class ApplicationController < ActionController::Base
    def paginate_by_sql(model, sql, per_page, options={})
       if options[:count]
           if options[:count].is_a? Integer
               total = options[:count]
           else
               total = model.count_by_sql(options[:count])
           end
       else
           total = model.count_by_sql_wrapping_select_query(sql)
       end

       object_pages = Paginator.new self, total, per_page,
            @params['page']
       objects = model.find_by_sql_with_limit(sql,
            object_pages.current.to_sql[1], per_page)
       return [object_pages, objects]
   end
end

Using paginate_by_sql is very much like using find_by_sql except that it returns a pair consisting of the paginator object and an array of the results. In the somewhat contrived example below, let's suppose we wanted a paged report that included selected columns from two tables, paged 20 records at a time. The code in the controller would look as follows.

sql = "select j.id, j.name,c.name as company_name from jobs j inner join companies on j.company_id=c.id order by j.activated_date DESC"

@job_pages, @jobs = paginate_by_sql Job, sql, 20


The markup in the view is exactly the same as it would be for standard pagination.
HTML:
  1. <%= pagination_links @job_pages %>
  2. <% for job in jobs %>
  3. <%= job.name %> <%= job.company_name %>  <br>
  4. <% end %>