Friday, March 15, 2013

Useful Lessons from Google Reader's Demise

Why Did Google Reader Die? And what free Web service will be next? by Farhad Manjoo

Anyone using web apps with some regularity, especially if you rely on them heavily, should read this article. What are web apps? Everything that does something for you online. I use Google Reader, Google Voice, Google Docs, Twitter,, Gmail, Google Plus, Diigo, Flickr, and others. Many are really useful and would not easily be replaced by desktop applications.

The bottom bottom line lessons from Farhad's article:

  • Consider an app's business model before investing in it--how does the company expect to keep it going? (And remember, you're investing in it simply by getting used to it, putting your data and time into it.)
  • Remember that your favorite service might just die anytime. Unlike desktop software, there is no possibility of continuing to use your legacy product you love so well. You might or might not get your data back.
  • If you use a web app that has a paid version, support it by paying, if you can afford it--how else do you expect it to remain viable?

Thursday, March 14, 2013

The End of Google Reader ... What Will You Use to Replace It?

Google has just announced the end of Google Reader on July 1.

Most people haven't even heard of Google Reader, but among those who have, it's quite popular. It's a free online service that lets you organize your  newsfeeds. Haven't heard of news feeds, either? They likewise may not be as hot as when they were developed some years ago, but the concept is great: just add websites or other information sources to your incoming feeds, and you'll be able to check all the new items from a single source on your computer. Forget visiting all your favorite blogs and news sources, just open your newsfeed and see everything in one place.

Many applications help you manage your newsfeeds, but Google Reader has been a popular one. It is very simple to use and is just there when you want it. Click on a title and the whole article opens up in the same window (if the feed included all the content) or a new window if you want to see the original. Mark the articles you want to remember, share, and so on.

My first reaction at hearing about the "retirement"--death seems a better word--of Google Reader was dismay. But then I thought, maybe there is a silver cloud. I haven't even looked for a better solution in years. Yes, well, I didn't see a need, and why fix what isn't broken. I still feel that way, but at least the death of Reader will force me to get out there and explore new options. This CNN article mentions Feedly, Pulse, Flipboard, and Zite. I'm not checking out Zite since it seems to an iOS-only app.  But they all have nice-looking home pages, and that's a start!

What about you? What news readers do you already use and love, or what are you planning to do now that Google Reader is terminal?

Friday, February 8, 2013

Warning to Airtel Nigeria Internet users

Airtel has a pattern "chopping" or exhausting the entire credit balance on your phone or modem if your data plan ends. This has happened to many people.

In my case, I got a notice that my plan would auto-renew in a few days, so I added 8000 naira credit to allow the auto-renewal. The next day, the plan ended because the gigabytes were exhausted. Airtel did not renew the plan despite the credit on my phone, they simply charged me the whole 8000 for "browsing without a plan," while never informing me that I was doing so.

Despite several useless phone calls to customer service (where they did not even know where my city Jos was), an hour in person with the local customer service, and an appeal to the manager, Airtel insisted that I was at fault, and they would not give a refund.

I know some other providers (MTN, I think) will drop the data connection until you explicitly say you want to continue without a plan, but Airtel conveniently "forgets" to let you know; you simply move with no notice from operating under your plan to exhausting your credit balance. While Airtel has provided good service, this fact would make me cautious about recommending it. I understand that Glo is also very good, but don't know how they handle this billing issue. Furthermore, Glo's Plans are cheaper with 7,500 naira for 8 GB as opposed to 8,000 naira for 5 GB with Airtel.

Thursday, June 7, 2012

Multiple Select Combo Form for Rails

I was trying to find the way to make a dropdown combo box with multiple selection for a Rails project. There are many tips in the documentation and online, but I could not find the right way to make sure the options were initialized to their proper values when the form is created. For example, if a book already belongs to categories "fiction" and "mystery," how to make sure that those are already selected and highlighted on the form. This is what I finally arrived at. A key point is that the column name needs to be “{collection}_ids” and not simply “{collection},” in order for the right choices to be automatically selected when the form is built. This example would be used in selecting multiple categories to apply to some model.
= fields_for :record do |form|
  = form.label :category_ids, “Categories”
  = :category_ids, 
       Category.collect {|x| [,]}, {}, :multiple => true
I think the standard update action in the controller will handle this without any special action. To do the update manually, you could just say

See the Rails doc at

Wednesday, April 25, 2012

Add Check-in, Check-out to Dropbox

Dropbox is a great solution for online backup and, to some extent, for simple collaboration. One limitation, however, is that there is no way to know when a collaborator has opened a file for editing. If two people edit a file at the same time, Dropbox will save both edited files which will not have conflicting changes.

Notifybox is a third-party solution to this problem. It only works with Microsoft Office documents and on Windows, but it does seem workable and is free for use on a single folder.

When you open a file within a monitored folder, a dialog pops up:


If you choose “Check-out,” you can go ahead and edit the file. When you save and close it, Notifybox informs you that it is now checked-in.

If you choose “Cancel” instead, a dialog box tells you that you should close the file without saving it. This isn’t enforced, so it’s up to the user to pay attention to the prompts.

If you try to open a file that is already checked out by someone else, a different message tells you that you should close the file without saving since it is already in use. It appears that all the potential users must be using Notifybox … I don’t think that it can tell if someone has checked out a file unless that person is also using Notifybox.

It’s a simple solution that bridges a gap between Dropbox and more complex version control systems that are likely too intimidating for most casual users.

A full subscription costs $6 monthly and allows you to monitor multiple folders and subfolders, and to encrypt and compress files in your Dropbox folder. The free version lets you monitor a single folder.

Wednesday, March 28, 2012

Dead Paypal Security Key

imagesJust on the off chance someone else has the same problem … My PayPal security key is several years old and last night it finally quit. It flashed these messages when turned on:

(some gobbledygook strange characters)
batt  75

I presume it means the battery was low, which wouldn’t be surprising. Well, should I just give it to my son to play with, or try to change the battery? I paid $5 for it but now they don’t even sell the key-chain model, and the credit-card model costs $30. Plus, I’m in Nigeria and it would take a good while to get a replacement.

I opened it up, which is fairly easy, and found a standard CR2032 lithium battery. I slid it out and slid in a new one. Uh oh, same error message! Well, let it sit for a while without the battery, I thought. So I took it out again, waited 5 minutes, then put the new one in. Now it just shows 88888888 no matter what! The button does nothing, the display does not turn off after a minute. Shorting some of the pads inside doesn’t do anything either. So now it’s no use even as a dumb toy.

It all makes sense, though. The key works by generating a 6 digit number every 30 seconds, and the number is verified by PayPal as belonging to your key. That means it’s tied to real clock time. If the battery is low and the unit thinks it may be unable to assure the accurate time, then it has to fail. Once that state has occurred, there should be no way to restore the correct state. Changing the battery doesn’t change the fact that the time has become suspect. Waiting 5 minutes before changing the battery probably put the key into a factory new state where it is waiting for programming.

Bottom line: If your security key fails, don’t bother trying to fix it. My own feeling is that it’s not worth $30 for the current credit-card-size key unless you have a weak password or are really careless with it, but then I might feel differently if I see a $3000 fraudulent charge on my account some day!

Saturday, November 13, 2010

Creating an Autocompleting Association Input in Rails3 + ActiveScaffold + JQuery UI

Summary: This is a way to add an auto-completing input on a form in Rails 3 + ActiveScaffold using JQuery UI. No method or template overrides are needed. Only one short Javascript function is used. Note that ActiveScaffold uses Prototype rather than JQuery by default, so existing projects based on Prototype will have to be adjusted to use JQuery instead (as well?) for this to work.

The Rails/ActiveScaffold project I’m working on has models for Member and Country. Each member belongs to a country—i.e. has a nationality. This is all done in the usual way using a key country_id in the member model to refer to the country:

class Member < ActiveRecord::Base 
belongs_to :country


class Country < ActiveRecord::Base 
has_many :members

The usual way of making an editing control in the member create and update forms is simply to add the line

config.columns[:country].form_ui = :select

to the members controller. This creates a dropdown select box populated with the labels and ids (values) of the countries table. If your list of options (countries in this case) is very large, however, it can be impractical to send the entire list for the user to select from. Hence the need for something like an Ajax-based autocompletion input. As the user enters characters, the newly forming string is sent back to the server, which returns a list of possible options that match the string to the current point. Type “Z” for the country and “Zimbabwe” and “Zambia” pop up.

I've spent several days trying to convert a select-box to an autocompleting-text-box in my Rails project. One thought was that perhaps I should have left well-enough alone rather than make the change. Even selecting a list of several hundred options for a select list does not add too much overhead: say 300 items of 20 characters each = 6 KB, hardly worth worrying about. Still, I’ve done it so will document what worked for me.

My second thought is actually a question: why isn’t it dirt-easy to do this in Rails and/or ActiveScaffold? Is it so rarely used? Or perhaps I simply missed the easy way even though I did quite a bit of searching. There is an auto_complete plugin but I couldn't get it to work with Rails 3 and ActiveScaffold--perhaps I could now that I understand more. I was greatly helped by Anup Narkhede's helpful example. In the end, though, I found a method that seems to me even easier than using the plugin!

How to Do It

Anyway, this is how I did it – I’m sure there are better ways. To start with an overview, the way I did this is:

  1. Adjust the member model so that we can set the country_id indirectly just by saying this_member.country_name='France'. To do this define accessor method's to read and write the member's country name. The read method looks up the country_id and returns the name, while the write method country_name= sets the country_id based on the name.
  2. Replace the form's input for country_id with one for country_name.
  3. Create a lookup function to be called by JQuery. For example, if JQuery sends 'Z' the function will return {'Zambia','Zimbabwe'}.
  4. Add the JQuery autocomplete function to the country_name input.

The Details

Start with these models:

class Member < ActiveRecord::Base 
  belongs_to :country

class Country < ActiveRecord::Base
  validates_uniqueness_of :name
  has_many :members

Step 1: add the accessor functions to the member model:

class Member < ActiveRecord::Base 
  belongs_to :country

   def country_name

   def country_name= (name)
     country = Country.find_by_name(name)
     self.country_id = if country

Step 2: Replace the form's input for country_id with one for country_name:

class MembersController < ApplicationController
  active_scaffold :member do |config|
    config.columns = [:name, :country_name]

Totally Optional Sidetrack: Before I hit on the technique of using the accessor methods in the model, I was overriding the MemberController update and create methods, as Anup Narkhede had shown. If for some reason you use a variation of that technique, there is one gotcha to be aware of. You cannot simply look up the id and insert it as params[:record][:country] unless the :country column was included in the form, because it will be ignored. This is part of the security of Rails 3: the user can't pass back arbitrary fields, because only those present in the form are processed. So, when I was overriding the controller update and create methods, I had to include the original :country column as a hidden field in the form. I'm guessing that this is also the reason that Anup first saved the country id in an instance variable @country, then used it in a before_create_save method rather than just adding the new element to the parameter hash.

Sidetrack: Note that you could compose any kind of string to use as the label rather than using "name." You would simply write the accessors for whatever you wanted. For example, you could use nationality rather than country name. Whatever is used, however, must be present and unique for each country so that the label-to-id lookup will return a single, valid country.

Step 3: Create a lookup function to be called by JQuery.

In app/controllers/autocomplete_controller.rb

class AutocompleteController < ApplicationController

  def country
    @countries = Country.where("name LIKE ?", "#{params[:term]}%").select("id, name")
    @json_resp = []
    @countries.each do |c|
      @json_resp <<

    respond_to do |format|
      format.js { render :json => @json_resp }

I would have preferred to put this into the existing CountriesController, but for some reason when I did that the response was very slow (2+ seconds). In any case, it's important to get the routing right. I used

  match 'autocomplete/:action'

Step 4. Set up JQuery

We need to add JQuery and JQuery UI to our project if they're not already present. Add to your default template (or elsewhere as long as it will be available)

<%= stylesheet_link_tag 
  '' %>

<%= javascript_include_tag '' %>
<%= javascript_include_tag '' %>

If you prefer, you can load the files to your own Rails public/stylesheets and public/javascript folders and link to them there.

Finally, add this short script to public/javascripts/application.js:

$(function() {
  $( ".country_name-input" ).live("click", function(){
      source: "autocomplete/country.js"

The country_name-input (be careful of the underscore and hyphen) is the class of the input. You could use an ID or other means of specifying it depending on what ActiveScaffold or other framework is generating.

The .live("click" piece is used to attach the JQuery UI autocomplete widget to country_name-input as soon as the input is clicked. We do this because, in ActiveScaffold or other Ajax-based views, the input may not exist in the DOM when the page loads, so some other event must be used to attach it. The demo and documentation for JQuery UI autocomplete are at

Everything is in place and should work now, once you put a few countries into the countries table.

Please comment if you have any questions, corrections, or suggestions!