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

and

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
end

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

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


class Member < ActiveRecord::Base 
  belongs_to :country

   def country_name
     Country.find(country_id).name
   end

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

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]
  end
 end

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 << c.name
    end

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

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 
  'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/ui-lightness/jquery-ui.css' %>

<%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.js' %>
<%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js' %>

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(){
    $(this).autocomplete({
      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 http://jqueryui.com/demos/autocomplete/.

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!

Tuesday, October 12, 2010

Change or Remove the Horizontal Line Above Footnotes in MS Word 2007

This should be a simple thing, right? If you don’t want a separating line above the footnotes, just remove it. In my case, the end notes flow to several pages, and a line is still being put at the top of every page, conflicting with the page header.
I look around and tried to find how to do this, but (a) the help documentation doesn’t seem to say, at least not in a place I thought to look and (b) most of the answers on the Web refer to the same set of instructions from years ago for Word 2003, even when they claim to be for 2007. The instructions are actually almost the same, except that Word 2007 no longer has a “normal” view, which is what you are supposed to start with in the instructions.
Anyway, here is how to do it in Word 2007
  • Select Draft from the View tab on the ribbon
image
  • Select “Show Notes” from the References tab. If you don't see “Show Notes,” be sure you're looking at “References” and not “Review.”
image
  • Now you should see your notes in the bottom pane, below this menu:
image
  • Since “All Endnotes” is the first item in the drop-down box, you would think that the other options would be “All Footnotes” or similar. However, this is where you select the separator formatting & other options. Select “Endnote Separator.” I suppose if you have footnotes, you will see “Footnote Separator.”
image
  • Now you can delete the separator or define a new one. I don’t know if a graphic can be substituted; I couldn’t find a way. Be sure to re-define the “Endnote Continuation Separator” also, if you need to; it’s what appears on subsequent pages.
image
Thanks to Rob van der Heijden whose post was the one that finally got me on the right track!

Saturday, April 3, 2010

Energy-efficient LCD Monitors

Many of us live in areas where electrical power is at a premium, so one of the threads I follow in this blog is low-power computing. It’s amazing how far you can stretch your amps and watts these days without loosing much computing power.

I’ve recently bought a Fit-PC and have an order in for the Fit-PC2 model. These are very small “desktop” computers that run on only a few (6-8) watts, but do all the usual things you need a computer to do. In contrast, typical laptops run at 30-60 watts.
I haven’t had a chance to try out the Fit-PC yet, because I need a monitor. Since I’ve been living out of a suitcase for the last 7 months, I’ve just been using a laptop. Now that I’m getting ready to return to Nigeria in two months, though, I’m looking for an energy-efficient monitor.

One review of energy-efficient monitors covers four models, but only one is in the size range I want for carrying overseas: the Lenovo Thinkvision L1940P. It runs at 18 watts, is rated 5 (of 5) stars by one reviewer on Amazon, and costs $222. However, Amazon also sells the 19-inch ViewSonic VX1932wm-LED, which runs at only 15 watts, costs $167, and is rated 4.5 stars by 7 users. That's the one I plan to buy. With that monitor and the fit-PC, I'll be using barely 23 watts when using the computer at maximum capacity. That means I could run it for 24 hours straight on half the capacity of a 100 amp-hour 12V storage battery. Of course, the performance is nowhere near that of a “normal” desktop or even laptop, but it should be fine for most tasks (browsing, email, word-processing). I’ll let you know!

Wednesday, March 31, 2010

Send and Receive Faxes Online – Free (or almost free)!

Faxes are becoming less essential in our lives as we can usually substitute scanned documents sent by email. Now and then, however, it’s useful or even necessary to send or receive a fax. There are a couple of low-cost (or free) solutions for this.

If your phone line is connected to your computer, then you can simply use the built-in fax services of you computer. However, that can be hard to set up. In any case, many of us no longer have working phone lines.

To send faxes, the service I like is FaxItNice. You can fax a document up to 10 pages long for $5. However, the better option is to sign up for the plan where you pay $20 up front, then pay only $0.18 per page whenever you want. Credits don’t expire. I’ve been using the service for 7 years and so far it has been quite stable and reliable. You just fill in name and number of the recipient, select a document you want to send (Word, text, PDF, images, and many other formats), and press the button to upload the document. You can preview the fax, add a cover sheet, then click to send. The service then sends the fax for you, redialing as needed until it gets through. You can try the system for free (one fax) here.

To receive faxes, which I need to do even less often than sending them, I use K7. It’s completely free. You just sign up to get a phone number which will then receive your faxes. When someone sends a fax, K7 will convert it to a fairly small image file and email it to you. You can also log in to view your faxes.

There are other services for sending and receiving faxes, but I haven’t found any better deals than these. Let me know if you have more suggestions.

Wednesday, March 10, 2010

Ushahidi to map conflict in Jos, Nigeria

temp I’ve been interested in Ushahidi for some time now but had never gotten around to installing it. If you haven’t heard of it yet, Ushahidi is a web-based, community-oriented tool for mapping events. It has been used for tracking civil unrest, events related to the recent earthquakes in Chile and Haiti, and so on.

I finally did set up a test installation a few weeks ago, just in time for the latest outbreak of violence around Jos. You can see it at here. The killings this week were south of Jos. I still have not figured out how to connect email to the Ushahidi server, so it is not receiving alerts or sending them out. Also, there is no mobile phone connection so it’s not receiving text alerts. Anyone who wants to help set these up would be welcome.

I have also set up a news feed to gather from many sources news stories related to the conflict centered in Jos. I’ve used Yahoo Pipes to pull in the headlines from CNN, Reuters, al Jazeera, AllAfrica.com, and so on, then extracted the ones dealing with the Jos situation. You can view the stories or use the (RSS) news feed to put the headlines into your favorite news viewer such as Google Reader.

Thursday, January 14, 2010

Trying out Free Smilebox – Flash Presentations from Your Photos and Videos

smilebox screenshot cropped I got an email from a friend today containing a family slideshow made at Smilebox. If you're not familiar with that site, it's an easy way to use your photos and videos to create a slideshow you can then email or post. The show is a self-contained Flash presentation that plays in any browser.

Since I just used Smilebox myself to make a little picture show, I thought might save you some time if I tell you more before you try it yourself. The most important point is that once you’ve assembled your show, you can’t change the style. Don’t spend a lot of time designing your show before you are sure which style you want to use.

The summary is that Smilebox is a good tool for a quick, simple slideshow. The results look professional. It probably isn’t the tool you want to use for your most important presentations both because it is inflexible.

I’ve created some samples with a few styles. They’re 2-8 MB each. See at

The Good

  • There is a free version.
  • You can email your show, post it on Facebook or a blog, etc.
  • There are many styles to choose from, from simple slideshows to “books” with interactive zooming to greeting cards and notes.

Limitations

  • You need a reasonably good Internet connection to use this (not an issue in developed world).
  • Each style has its own methods for you to arrange and caption the photos. You have to experiment and learn each one. For example, the “Slide” style has a sorter view where you can drag and drop photos to reorder them, but most styles don’t. You may enter captions directly on the photo in some cases, or on the page in others, or have to click the enlarge button first.

Limitations on Free Version

For $3.00 you can avoid the following restrictions on a single presentation. You can also pay $6 per month or $40 per year to have the full version.
  • Supported by ads. As usual, you can’t know what ads might appear alongside your show.
  • Each style has its own music. You typically get three choices with each style. With the paid version, you can choose from hundreds of pieces of stock music or use your own.
  • The full version can play full-screen.

The Bad

  • The program does not use titles, captions, descriptions and so on that you may have already embedded in your pictures. You have to enter all captions whenever you start a new project.
  • Once you’ve committed to a style, you can’t change it without starting over. That is, you can choose a different style, but then you have to arrange and caption your photos all over again.
  • The styles are fixed in stone. That is, there is nothing you can modify, not fonts, position on page, layout of a given page, and so on. Of course, this is part of the reason that the program is simple.
  • The interface is rather slow. I think all the whole thing is written in Flash.
Let me know if you try it and have any further observations or comments.