Third ‘morning coffee’ meeting in Amsterdam

Thijs van der Vossen, 26 Jan 2007, 08:40 in ruby on rails and events (edit).

Time for another one. The goal remains unchanged: a good chat about our experiences with Rails, Django, Seaside and other next generation web frameworks over a strong cup of coffee.

Photo by Rodney Ramdas

When: Thursday, February 22nd, 2007, 9:30 AM

Where: The Coffee Company on the corner of the Nieuwe Doelenstraat and the Kloveniersburgwal in Amsterdam

Please leave a comment to tell us you’ll be there or if you have any questions.

29 comments

Dynamic forms with the repetition model

Manfred Stienstra, 25 Jan 2007, 12:06 in ruby on rails, javascript, and web (edit).

I’m sure we’ve all been there; trying to save a list of associated objects together with the instance they belong to. Fortunately with the right tools this can be really simple.

Let’s assume we have a question in a questionnaire and need to specify an arbitrary number of options to this question. We could construct the following database schema.

create_table :questions do |t|
  t.column :stem,        :text
end

create_table :options do |t|
  t.column :question_id, :integer
  t.column :label,       :text
  t.column :feedback,    :text
  t.column :correct,     :boolean, :default => false
end

There are basically three ways I know about to assign multiple options to a question from one page. The first option is to create a Question instance in the database before rendering the form so we can use remote_form to send an Ajax request and directly associate the Option instance. An advantage of this solution is that all data is directly saved to the database, which makes losing any data less likely. Another advantage is that the functionality is spread nicely over the responsible controllers. First you perform a create on the QuestionsController, after that you perform multiple creates on the OptionsController. The disadvantage is that you have to create a Question with default values or by circumventing the initial validation. This could generate some ‘blank’ Question instances in the database which you will have to garbage collect.

The second option is a slight variation on the first option. Instead of creating a Question to link the Options to you keep all the generated Option id’s in the session and link them to the Question after validation. This solution also benefits from nice separation of concern in the controllers, but on the downside it also leaves you with unlinked Option objects you will have to garbage collect.

The third option is to keep all the information about the Questions and Options in the DOM tree of your from and post it all at once. This used to be hard, requiring a lot of custom JavaScript and browser tricks. Fortunately WHATWG is here to help; Web Forms 2.0 defines a repetition model for repeating form controls. Browser support for these interaction models is years away (except for Opera 9, which has an experimental implementation), that’s why there’s a JavaScript library to accelerate the adaptation.

It’s really easy to use the library in your Rails application. Download the repetitionmodel library, extract the zipfile and put the javascript files in public/javascripts. When you’re done with that we can get back to coding our application. Include the JavaScript file somewhere in your views.

<%= javascript_include_tag 'repetition-model-p' %>

We just mentioned that we want to send the entire form at once, we can use validates_associated to make sure the Question is never saved when the options aren’t valid. This allows you to easily validate all the information from the form at once. The models to go with the database look something like this.

class Question < ActiveRecord::Base
  has_many :options, :dependent => :delete
  validates_presence_of :stem
  validates_associated :options
end

class Option < ActiveRecord::Base
  belongs_to :question
  validates_presence_of :label
end

Build the new and edit forms for the QuestionController like you would normally do. A the bottom of the form we will add the HTML to edit the options.

<h2>Options</h2>
<ol id="options">
  <%= render :partial => 'options/option', :collection => @question.options %>
  <%= render :partial => 'options/option', :object => Option.new,
    :locals => {:option_counter => '[option]'} %>
</ol>
<p><button type="add" template="option">New option</button></p>

The first render is for all the existing options, the second render is for what the repetition model calls a template, the template should always be the last in the list of controls.

In app/views/options/_option.rhtml we put the following. This partial doubles as a template for new controls and as a partial for existing options in the database.

<% if option_counter == '[option]' -%>
<li id="option" repeat="template" repeat-start="0">
<% else -%>
<li repeat="<%= option_counter %>">
<% end -%>
  <div>
    <div><label>Label</label></div>
    <%= text_area_tag "options[#{option_counter}][label]", option.label,
      :rows => 1, :cols => 40 %>
  </div>
  <div>
    <div><label>Feedback</label></div>
    <%= text_area_tag "options[#{option_counter}][feedback]", option.feedback,
      :rows => 1, :cols => 40 %>
  </div>
  <div>
    <label><%= radio_button_tag "options[correct]", option_counter, option.correct?,
      :id => "options_correct_#{option_counter}" %> Correct</label>
  </div>
  <div>
    <button type="remove">Delete option</button>
  </div>
</li>

In the HTML you see some extra attributes used by the JavaScript to determine what to do with them. When the partial is rendered with an new Option, the template is flagged by setting the repeat attribute to template. The id of this element is used as a handle for our controls, in our case this is ‘option’. The repeat-start attribute tells the javascript how many empty controls to generate initially from the template, we don’t want any so we’ve set it to 0. Note that we explicitly set the option_counter to ‘[option]’, this is the variable notation for the repetition model. When a new control is instanciated from the template this variable is replaced by the the index of the new control. The first control gets index 0, the second gets index 1 and so forth.

When the partial is rendered with a collection, the magic variable option_counter is set to the index of the collection every time the partial is rendered. We use this index to set the repeat attribute of the list item, this signals to the JavaScript that this is an already instantiated control. The JavaScript will start counting from the largest index when it instantiates a new control.

Finally we want the user to add and remove option controls in our page, this is done with the ‘New option’ and ‘Delete option’ buttons. Their type attribute signals what we want the JavaScript to do with the repetition blocks. In case of the ‘New option’ button the template attribute tells the JavaScript which template to instantiate.

In addition to managing the controls and template in the DOM tree, the JavaScript also takes care of disabling buttons on appropriate times and setting the CSS display property of the template to none. They really thought of everything.

The advantage of this solution is that you can use all the standard Rails tricks to keep your database clean. The biggest disadvantage is that the create method in your QuestionsController becomes a lot more complex.

Let’s hope native browser implementations follow quickly.

8 comments

Customer choice

Thijs van der Vossen, 23 Jan 2007, 20:10 in broken (edit).

If you search for Windows Vista on Amazon, you get this:

Microsoft Windows Vista Ultimate FULL VERSION, Microsoft Windows Vista Ultimate UPGRADE, Microsoft Windows Vista Home Premium UPGRADE, Microsoft Windows Vista Home Premium FULL VERSION, Microsoft Windows Vista Ultimate UPGRADE Limited Numbered Signature Edition, Microsoft Windows Vista Home Basic UPGRADE, Microsoft Windows Vista Business UPGRADE, Microsoft Windows Vista Business FULL VERSION, Microsoft Windows Vista Home Basic FULL VERSION, Microsoft Windows Vista Home Premium Upgrade Additional License Pack, Microsoft Windows Vista Home Basic Upgrade Additional License Pack, Microsoft Windows Vista Home Premium 64-bit for System Builders, Microsoft Windows Vista Ultimate Upgrade Additional License Pack, Microsoft Windows Vista Ultimate 32-bit for System Builders, Microsoft Windows Vista Business Additional License Pack, Microsoft Windows Vista Business Upgrade Additional License Pack, Microsoft Windows Vista Ultimate Additional License Pack, Microsoft Windows Vista Ultimate 64-bit for System Builders, Microsoft Windows Vista Ultimate 64-bit for System Builders - 3 pack, Microsoft Windows XP Professional SP2B for System Builders with Vista Tech Guarantee Coupon, Microsoft Windows Vista Ultimate 32-bit for System Builders - 3 pack, Microsoft Windows Vista Home Basic 64-bit for System Builders, Microsoft Windows XP Media Center Edition 2005 SP2B for System Builders with Vista Tech Guarantee Coupon (CD-ROM), Microsoft Windows Vista Home Premium 32-bit for System Builders, Microsoft Windows Vista Home Premium Additional License Pack, Windows Vista Home Premium SPANISH FULL VERSION, Microsoft Windows XP Home Edition SP2B for System Builders with Vista Tech Guarantee Coupon, Microsoft Windows Vista Business 64-bit for System Builders, Microsoft Windows XP Pro X64 Edition SP2B for System Builders with Vista Tech Guarantee Coupon, Microsoft Windows Vista Business 32-bit for System Builders - 3 pack, Microsoft Windows Vista Home Basic 64-bit for System Builders - 3 pack, Microsoft Windows XP Tablet PC 2005 SP2B for System Builders with Vista Tech Guarantee Coupon (CD-ROM), Microsoft Windows Vista Business 32-bit for System Builders - 3 pack, Microsoft Windows Vista Home Basic 32-bit for System Builders - 3 pack, Microsoft Windows XP Pro SP2B for System Builders with Vista Tech Guarantee Coupon, 3 pack, Microsoft Windows Vista Home Premium SPANISH UPGRADE, Microsoft Windows XP Media Center 2005 for System Builders with Vista Tech Guarantee Coupon, 3 pack (CD-ROM), Microsoft Windows XP Pro X64 SP2B for System Builders with Vista Tech Guarantee Coupon, 3 pack, Windows Vista Business SPANISH FULL VERSION, Microsoft Windows Vista Home Basic SPANISH UPGRADE, Microsoft Windows XP Home SP2B for System Builders with Vista Tech Guarantee Coupon, 3 pack, and Windows Vista Business SPANISH UPGRADE.

Right.

2 comments

Obama makes me want to listen

Thijs van der Vossen, 22 Jan 2007, 10:41 in web and video (edit).

Both Hillary Clinton and Barack Obama use web video to announce their exploratory committees.

Screenshot showing both Hillary Clinton and Barack Obama’s announcement video on the web

Obama is publishing video through Brightcove. This means you can easily email, link to, or embed the video. You also get a channel you can subscribe to using RSS.

Hillary is using her ‘own’ player which means there’s none of this nice stuff.

Another smart touch on the Obama website is the low-bandwidth download for people on dailup and a link to the transcript.

It’s also interesting to compare the production. In the Hillary video the camera is panning from left to right and back all the time. Apart from making you seasick this increases the size of the video file because there’s a lot more information that needs to be encoded.

The Obama video uses a single fixed head-and-shoulders shot. This seems to work very well for these kind of messages on the web; he’s close enough to make it feel like he’s talking to you directly, but not so close that it’s uncomfortable. Hillary is too far away over there on the couch in the first part of the video, and then a little too close and personal when they switch to close-up.

The sound is way better in the Hillary video. Obama sounds thin and ‘canned’, probably because of too much compression.

To me, the Obama video appears to be serious and personal. The Hillary video somehow made me feel I was watching a life insurance commercial. What do you think?

3 comments

Logos redesigned for Web 2.0

Thijs van der Vossen, 21 Jan 2007, 13:19 in design (edit).

Logos redesigned for Web 2.0

Started in this Yah Hooray thread, there’s more on Flickr.

7 comments

Rails 1.2 Released

Manfred Stienstra, 19 Jan 2007, 16:49 in ruby on rails and unicode (edit).

Today the Rails Core Team released Ruby on Rails 1.2. The long awaited new version is of course full of features and fixes. The thing we’re most excited about is the inclusion of ActiveSupport::Multibyte. But it doesn’t stop with multibyte support, Rails now ships with UTF-8 as a default in all parts of the framework, something we couldn’t have dreamed of a year ago.

1 comment

Fingertips is hiring

Thijs van der Vossen, 02 Jan 2007, 12:58 in ruby on rails (edit).

We’re looking for a full-time Ruby on Rails developer. If you’re interested, please send email to thijs@fngtps.com

6 comments