Art

Girls Rock

February 14th, 2008

This movie looks fantastic. Opening March 7th, in SF, Berkeley, Portland, Seattle, New York and Chicago.

This is my dear friend Dan’s daughter Lucia. Oh, what a beautiful little person!

Terri on Tour

December 1st, 2007

Terri is on tour with Rubies and recently played a festival in Bergen, Norway. Check out Pitchfork’s Article for some great photos. Samples of the music on their page and their myspace page My domain name, the framework this blog was written in and I all wish we could have traveled back to the north country to see her play.

When I used to work at the Exploratorium I would spend as much time as possible after hours learning to use the wood shop. I cut my teeth on a design by Creative Playthings, a company that was something of a children’s toy think tank of the post war modernist 50s. The design won my heart with its simplicity- a rod, two arcs and brightly colored ball. They are pretty simple to reproduce, you just build a form each for the curves, a simple notch and slot system for the smaller arc to slide in the larger arc, a hole for the rod and ball assembly, finish, and your done. Regardless, it took me several tries to get it right- the first prototype had too sever of a pitch to the major arc, and Felix would tip backwards and off the rocker! Once I got it right, i was able to crank them out at the super quick pace of one every few months and would give them away to close friends who had recently given birth. Here is a video of one in the wild (That’s Henry Holden, son to a mentor developer of mine at the museum. Notice the other playthings surrounding Henry- toy bucky balls!) :

Technology

Juggernaut is pretty slick. I am building an application which I hope will communicate a certain vitality by showing live usage of other users in real time. To push out changes to all currently connected browsers I simply call


  render :juggernaut =>  {:type => :send_to_channel, :channel => @channel} do |page|
    page.replace 'section' :partial => 'section'
  end

As you can tell from the snippet, the syntax is identical to the render :update syntax only you can call out which browsers receive the update by specifying channels or clients. Its that transparent.

The claim is that the vast majority of browser will support connections to the juggernaut server, but, of course, you can’t design as if all browsers will flawlessly be able to connect and stay connected. The way I handled not knowing if everybody is connected is pretty simple.

  1. employ optimistic locking (if you potentially have a bunch of users all modifying the same data, you probably already do this, or some other form of locking which takes care of the data integrity problem).
  2. check to see if the updating client has a live juggernaut connection. If they do, they’ll get the update through juggernaut along with everybody else on the channel. Otherwise, send the update over juggernaut AND the traditional way with render :update. This way the updating client will be certain to get the update.

This second step solves the user feed back problem- it pretty much guarantees that the updating client will see the results of the update, and won’t try to repeatedly recommit the update.

Finding out if the client is connected takes two minor code changes. In juggernaut_helper.rb set line 23 to


  javascript_tag "juggernaut = new Juggernaut('#{options.to_json}');" 

In prototype.js insert the following line after line 1208:


  params['juggernaut_connected'] = juggernaut.is_connected;

With these changes all async requests to rails include the juggernaut_connected value in params. So, in your controller methods which call juggernaut updates you can do:


    new_content = lambda do |page| 
      page.replace 'stuff', :partial => 'stuff'
    end

    render :juggernaut => {:type => :send_to_channel, :channel => @channel}, &new_content
    render :update, &new_content unless params[:juggernaut_connected]

It turns out that extending the standard rails types isn’t that hard, but it does take a fair amount of book-keeping.

Say you are recording birthdays, but don’t want to be so rude as to insist on knowing peoples age. That is, you want to know when to wish them happy birthday, so you only really need to know the day of the year they were born on; you don’t really need to know the year. Optionally, you should record the year if you know it because you’ll want to wish them a happy x’th birthday if you do know the year.

The steps to extending an ActiveRecord attribute go something like this:

  1. create module that extends attribute type
  2. create migration to store additional data (i chose to serialize hash)
  3. add def attribute= method
  4. add def attribute method
  5. tweak rails helper to make form entry appropriate for the new type, if necessary (add a blank option to the year select, in this case)
  6. tweak controller if necessary- alter attributes hash, recompose type and assign to attribute hash)
  7. be sure not to overwrite original attribute’s to_s method, cause its used in dumping to the database

Step 1: Create a module that extends attribute’s type


module ApproximateDate
  def self.extended(obj)
    class << obj
      def precision=(value)
        @precision = {:year => true, :month => true, :day => true}.merge(value)
      end

      def precision
        self.precision = {} unless @precision
        @precision
      end

      def known?(*tests)
        self.precision = {} unless @precision
        return tests.all?{ |test| @precision[test] }
      end

      def approximate_string 
        # can't simply overwrite to_s, as active record uses it to write the date value to the database
        return strftime("%m/%d/%Y")                       if known?(:year, :month, :day) && !nil?  
        return strftime("%B") + ' ' + day.ordinalize      if known?(:month, :day) && !nil?
        return strftime("%Y")                             if !known?(:month) && !nil?
        return strftime("%m/%Y")                          if !known?(:day) && !nil?
        return ''
      end

    end
  end

  def self.make_approximate(date, precision)
    date.extend ApproximateDate 
    date.precision = precision if precision
    date
  end
end

This code takes a date, adds a precision hash which records which fields of date are known and a few utility methods for querying whats known and printing nice human readable forms of the new datatype. This code lets you do things like:

birthday = Date.today                                                                  # today is my buddy's birthday
ApproximateDate.make_approximate(birthday, :year => false)       # but the dude is shy!  he won't tell me how old he is!
pp "dude was born on #{birthday.approximate_string}"                   # dude was born on Febuary 5th

Step 2: Create migration to store additional data (i chose to serialize the precision hash into a single field in the database)


class AddApproximateDatesToRelation < ActiveRecord::Migration
  def self.up
    add_column 'Relations', :date_of_birth_precision, :string
    add_column 'Relations', :date_of_death_precision, :string
  end

  def self.down
    remove_column 'Relations', :date_of_birth_precision
    remove_column 'Relations', :date_of_death_precision
  end
end

Step 3: Add def attribute method

On the model add:

def date_of_birth    
  date = super
  ApproximateDate.make_approximate(date, date_of_birth_precision) unless date.nil?
end
This method overwrites then calls the standard AccectiveRecord attribute getter, but extends the Date on the way out to make it an ApproximateDate.

Step 4: Add attribute assignment method


def date_of_birth=(date)
  if date.respond_to? :precision
    self.date_of_birth_precision = date.precision 
  else
    self.date_of_birth_precision = nil
  end
  super(date)
end
Here we check to see if the Date passed in was an ApproximateDate, and if so, we pull out the precision, and store it. Otherwise, we need to clear the precision information, as none was passed in.

So far we’ve done pretty much what you would expect would be necessary- combine the two fields when an accessors is called, and split the into columns when the data is being stored. The following steps are necessary to format the data for the user

Step 5: Tweak rails helper to make form entry, if necessary (add ’’ option to select, in this case)

We are going to need to add new blank option to the standard date select, so the user will not have to select a year value, should he choose not to. The following code requires browser detection, as IE handles DHTML adding of options in a very different way than other browsers.

Add this to your javascript library:

var prependOption = function(select, text, value) {
    select = $(select);

    if(BrowserDetect.browser == "Explorer") {
        var optn = document.createElement("OPTION");
        optn.text = text;
        optn.value = value;
        select.options.add(optn, pos);
    }

    else new Insertion.Before(select.options[0], '<option value=' + value + '>' + text + ' </option>');
};
And this to your rails helpers:

def make_select_approximate(select, date_part_known)
  out = javascript_tag("prependOption('#{select}', '-', '');")
  out << javascript_tag("$('#{select}').options[0].selected = true")  unless date_part_known
  out
end

This code simply sits on top of the standard rails date select helpers. The javascript adds the additional blank option, and the rails helper calls the javascript and additionally selects the blank option if this data is not known.

Step 6: Tweak controller if necessary- alter attributes hash, recompose type and assign to attribute hash)

The flip side of tweaking the rails helper is we need to recombine the attributes coming back from the form post.

day   = attributes["#{date_name}(3i)".to_sym]
month = attributes["#{date_name}(2i)".to_sym]
year  = attributes["#{date_name}(1i)".to_sym]

# Create date with data where known
date = Date.new( (year.empty? ? 1 : year.to_i), (month.empty? ? 1 : month.to_i), (day.empty? ? 1 : day.to_i) )
# Set precision when data unavailable
ApproximateDate.make_approximate(date, :day => !day.empty?, :month => !month.empty?, :year => !year.empty?)
# strip out rails multiformelement helpers from input hash
["#{date_name}(1i)", "#{date_name}(2i)", "#{date_name}(3i)"].each{ |key| attributes.delete(key.to_sym) }
# replace with approximate date
attributes[date_name.to_sym] = date

That’s it. Phew!

One last note: be sure not to overwrite the original attribute’s to_s method- rails ORM uses this method to write the value to the database. That’s why the method approximate_string is not named simply to_s

Rails redirect_to and AJAX

February 4th, 2008

A problem arises when an asynchronous request comes in to a Rails controller and you want to redirect to a different action for an rjs response. Because redirect_to actually sends a “302 Moved” HTTP response, causing a full round-trip to the client and back, the request type is altered and respond_to now gets the wrong format request type.

Here’s a solution, the only one I know of:

  render :update do |page| 
    page << "new Ajax.Request('/url_for_redirect');" 
  end

I encountered this problem when I wanted to handle a sortable_element reorder like this:

  def order
      @order = params[:list]
      @order.each_with_index do |photo_id, i|
        photo = Photo.find(photo_id)
        photo.position = i
        photo.save
      end

      #right about now i'm wishing redirect_to perserved request types
      render :update do |page| 
        page << "new Ajax.Request('/admin');" 
      end
  end

There has to be something better, since this causes yet another round-trip to the server. Anybody have a better way to handle this problem?