.

Using an auto_complete to ensure uniqueness

The Problem

Occasionally there is a need to have a user enter a unique string. For example, if you want to ensure that a new user’s login id is not used by someone else. The traditional rails way of doing this is to set up a ‘validates_uniqueness_of’ validation on the model and then catch the error when you try to save the record.

From the user’s point of view, this can be a horrendously painful experience that can be akin to trying to outsmart the Sphinx.

Form: “please enter a unique login id’
User: “john smith”
Form: “Wrong, guess again!”
User: “jsmith”
Form: “Nope, getting warmer”
User: “jsmith1″
Form: “You wish! Keep trying!”
User: “as;ldfkjasd;flkajsdf;lakjsd”
Form: “Ha! your id must be only numbers and letters!”
User: “!@!$!@!#!@#!@#!@#%*(#^($!!!!!!!”
Form: “Sorry, wrong again!”
* user navigates to youtube *

The biggest problem here is that there is no feedback to the user if the value they selected is valid until they submit. Some forms will also force you to retype your new password everytime this fails as well. Double ouch!

Solutions

  1. offer suggestions for valid responses when it fails the first time. Not exactly the best, you might as well autogenerate their id for them and hope they don’t forget it.
  2. provide feedback with AJAX to let them know if the value is ok.

As you might have guessed from the title of the article, I’m going to show you how to do this with a standard rails auto_complete text field.

  1. # view file
  2. < %= text_field_with_auto_complete :user, :login_id %><div id=login_error></div>
  3.  
  4. # controller file
  5.  
  6. def auto_complete_for_user_user_name
  7.   @user = User.find_by_user_name(params[:user][:user_name])
  8.    render :update do |page|
  9.      page.replace_html ‘login_error’, (@user ? "Login id already in use" : "")
  10.    end
  11. end

That’s it. Anytime the auto_complete matches a record, it will change the ‘login_error’ div to indicate there’s a problem.

Net result…. a much better user interface experience and much happier users. (more…)

Another blindingly obvious way to disable a submit button when pressed

Probably the simplest and least problematic way to disable a submit button when pressed.

  1. # put this in your ‘application_helper’ file
  2.  
  3. def commit_tag(title, html_options={})
  4.   submit_tag title, html_options.merge(:id=>’commit’, :onclick=>’$("commit").disabled=true;’)
  5. end

Then just use ‘commit_tag’ instead of ’submit_tag’ in your form.
Strictly speaking, you don’t really need to give the button an ‘id’, but I do because it has the bonus side effect of making it easy programmatically disable the button from RJS templates.

One reason this approach is superior (I think) to an AJAX call is that there is less of a chance that an over-enthusiastic user will be able to click the button again before the AJAX response renders.

ruby-units 0.3.3

The latest version of the ruby-units gem has just been released.

Installation

gem install ruby-units
or
gem update ruby-units

Features

  1. Significantly improved speed
  2. Will use the ‘Chronic’ gem to interpret times/dates if loaded
  3. some nice time helpers.
    ‘1 day’.from ‘now’ #=> Wed Oct 04 18:27:13 EDT 2006
    ‘1 day’.ago #=> Mon Oct 02 18:38:56 EDT 2006
    ‘7 days’.before ‘1/1/2007′ #=> Mon Dec 25 00:00:00 EST 2006
    ‘7 days’.after ‘12/25/2006′ #=> Mon Jan 01 00:00:00 EST 2007
    ‘days’.since ‘1/1/2006′ #=> 275.436 d
    ‘days’.until ‘1/1/2007′ #=> 89.7683 d

    (works for sec, min, hours, days, weeks, fortnights, years, decades, centuries….
    but not months).

    and some others..
    these helpers will automagically give you a DateTime object
    if a Time object won’t work.

    ‘years’.since ‘1/1/1900′ #=> 106.756 y
    ‘50 years’.from ‘now’ #=> 2056-10-02T18:46:55Z
  4. units can now identify themselves (sort of..)
    ‘60 mph’.unit.kind #=> :speed
    ‘9.8 m/s^2′.unit.kind #=> :acceleration
  5. some new constructors
    Unit(10,’m') #=> 10 m
  6. Now throws an exception if it donsn’t understand a unit (during creation)
  7. Temperature handling improved
    “0 tempC”.unit #=> 273.15 degK
    “310.15 degK”.to(’tempC’) #=> 37 degC
  8. Trig functions can accept angular units
    Math.sin(’90 deg’.unit) #=> 1.0
    Math.sin(’100 grad’.unit) #=> 1.0
« Previous PageNext Page »