Showing posts with label howto. Show all posts
Showing posts with label howto. Show all posts

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!

Saturday, July 4, 2009

Create a high-security vault for your data in 5 minutes

truecrypt_iconIn the last article, Protecting your sensitive data with TrueCrypt, I gave an overview of what Truecrypt can do for you: make an encrypted virtual hard drive, encrypt an entire partition, or encrypt an entire hard drive. This time, we'll see how to make the virtual hard drive in at most 5 minutes. Rather than write my own tutorial, I direct you to the step-by-step TrueCrypt Beginner's Tutorial with full screen shots.

Instead of another tutorial, I'll summarize the steps, add a note or two, and try to give a little more explanation of what is happening in this method.

Why use TrueCrypt?

First, why use Truecrypt rather than one of the many, many other encryption programs?

  • Compatibility: TrueCrypt runs on Microsoft systems from Windows 2000 upward, on Mac OS X 10.4 and 10.5, and on Linux. (According to this Wikipedia article, only one of the other 45 disk encryption programs work on all three systems, and that one is not open source).
  • Price: Free. Not shareware, not trial-ware, not "free download," but just free, period.
  • Open source: This means that anyone can examine the program's instructions to see how it all works. This means that many people can be working on improvements and bug-fixing. More importantly, though, the transparency of open source makes it hard for any security flaws to remain undetected.
  • Wide use. TrueCrypt is one of the most widely used encryption programs. The site reports over 10 million downloads to date.

That said, the most important thing is to protect your sensitive data somehow and to use a well-supported, respected encryption program. If you like experimenting, there are many programs out there. TrueCrypt can be a complicated program with all kinds of options, but it's quite easy to use the most important features.

Overview

Goal

banksafe What will you accomplish when you follow the tutorial?

  • Within a few minutes, you will have a new "drive" M: on your computer where you can safely store sensitive information. You can use it like any other drive--create files, drag-and-drop files into our out of folders on the drive, even use a folder on the drive as your "My Documents" if you like.
  • Though in action you see a new drive M:, all the data is kept in a container file that can only be unlocked ("mounted") using TrueCrypt and your passphrase.
  • While your new drive is mounted, you will not know or care that your files are encrypted. When you turn off your computer or lock ("dismount") the drive, the data will be invisible, safe from any prying eyes.
  • You can copy or move the entire encrypted drive, as a single file, to a different location such as a USB flash drive or another computer. This is good for backup.

Steps

Here's a high-level explanation of the 18 steps in the tutorial.

  • Step 1: Download and install the program.
  • Steps 2-12: Create the container file. This only has to be done once.
  • Steps 13-18: Mount the container file for use. You do this every time you want to unlock and access your data.

Precautions

  • You are making a data vault or safe, and your passphrase is the combination to the lock. There is no backup, no spare key or emergency button to use to recover your data if you lose or forget your passphrase. In most cases, it is probably best to record your passphrase somewhere safe rather then rely on your memory. Obviously, you don't want to keep it somewhere where a thief will see it, such as in your computer bag. Depending on your situation, you may not even want to keep it in writing in your home or office, but do consider keeping it somewhere.
  • Putting your information onto an encrypted drive is only one part of security. Do not neglect other parts; a chain is as strong as its weakest link.

OK, let's do it

Now, go to the tutorial and follow it step by step, referring to these notes as you do.

  • Step 1. Downloading and installing TrueCrypt. Ideally, you should download the program directly from TrueCrypt so that you get the most up-to-date, "pure" version.
  • Steps 2-5. Telling TrueCrypt you want to create a virtual drive. Just click the buttons as shown, no choices to make here.
  • Step 6. Specify location and name of container file. Attention: be sure to read the explanation in the tutorial. Although it might appear that you are to select an existing file to encrypt, this is not true. Rather you are giving the program the location and name of a file to create. This new file will be the "container" for your virtual drive. If you select an existing file, it will be erased, not encrypted!
  • Steps 7-8. Having chosen a name for your container file, you just press "next" two times.
  • Step 9. Tell TrueCrypt how big to make your virtual drive, how much data you will be able to store in it. TrueCrypt will create a container file of this size, so you will need at least that much free space in the location you have chosen. Don't make it too big if you plan to copy the entire thing onto a flash drive.
    Optional note: If you choose to make the container "dynamic" (Step 11), it is very small at first and only grows as you add files. In this case, the size you select in step 9 is the maximum size. If you do not make the container dynamic, then the container file will be this maximum size from the very beginning, even though it contains no data.
  • Step 10. Choosing a passphrase. While you are just testing, you can use a simple passphrase. For serious use, however, be sure to read the guidelines about how to make a secure passphrase.
  • Step 11. Select format type. Just follow the instructions, moving your mouse around randomly for a while to help make the encryption strong, then click Format.
    Optional note: For advanced use, you can use a format other than the default FAT. For large virtual drives in Windows, you might consider using NTFS.
  • Step 12. Finishing up. Now the container file is ready to use.
  • Steps 13-18. Mounting the container as a virtual hard drive. Although this occupies six steps in the tutorial, it is really simple. First, you choose a drive letter to assign to the new drive (step 13), then you tell TrueCrypt which container file to use (i.e., the one you just created) (steps 14-16). Finally, you enter your passphrase for that container file and mount it (steps 17-18).

At this point, your new drive M: is ready to use just like any other drive. Remember that you data is exposed as long as the drive is mounted; if someone steals the computer while you are working on it, M: will be unlocked until the computer is shut down. Depending on the situation, you may want to manually dismount it when you leave the computer or when you do not need to access the secure files.

Finally, read the small print at the end of the tutorial and realize that your original, unencrypted data is still present on your original drive even after you delete it--that's why file-recovery programs work. To permanently remove it, you need to use a disk wiping program with the option of erasing all unused disk space. See Purge Your Hard Drive for a good explanation. One wiping program is Heidi Computer's Eraser. Some others are reviewed in Best Free Secure Erase Utility.

Even then, how do you know that you have deleted all the files that contain sensitive data? What about backups, email folders, temporary files, obscure files in the Application Data folder, the paging and hibernation files? You really don't know. That's where whole disk encryption comes into play. It may seem a little scarier to think of altering your whole hard drive, but it's actually easier than making a virtual drive, and it eliminates all these residues of the information you want to protect. You will not need to worry about wiping or shredding your files, either. I'll cover whole disk encryption next time, in a much shorter article I hope!

Photo of safe by rpongsaj on Flickr, http://www.flickr.com/photos/pong/ / CC BY 2.0