Posts Tagged ‘upload’

Apotomo can upload files with AJAX!

Wednesday, August 20th, 2008

Note: This post was updated in March 2010- consider it hot.

The Problem

Uploading files with AJAX is a bitch, as JavaScript doesn’t allow uploading from the local filesystem.

A work-around is the IFRAME remoting pattern where the form is sent to an iframe and the response is processed by the iframe’s parent page.

The traditional Rails solution

The setup for this work-around in Rails is quite expensive. This small plugin responds_to_parent does help a lot.

However, even the plugin encourages a common rails sin: knowledge spreading.
The controller action, the RJS code and the form template, they all need to know about the iframe.

How Apotomo does it

The philosophie in Apotomo is

the programmer implementing the uploading form does not even have to know about the upload problem and the IFRAME solution

Let’s look at a small form.

app/cells/uploading_form.rb

1
2
3
4
5
6
7
8
9
10
11
12
class UploadingForm < Apotomo::StatefulWidget
  def display
    respond_to_event :submit, :with => :process
    @user = current_user
    render
  end
 
  def process
    @user.update_attributes(param(:user))
    render :view => :display
  end
end

The uploaded image is added to @user in the #process state (line 9).

app/cells/uploading_form/display.html.haml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
%h3
  Settings for
  = @user.username
 
= form_to_event(:submit, :multipart => :true) do
 
  Email: 
  = text_field :user, :email
 
  Avatar: 
  = file_field :user, :avatar_path
  = image_tag @user.avatar_path, :width => 90
 
  = submit_tag "Update"

All of the work is done in #form_to_event, which adds the iframe and form parameters when :multipart => :true is passed.

No magic!

After the form has been submitted through the iframe a :submit event is triggered in the form widget and Apotomo’s event cycle kicks in. The content of updating widgets (especially the form widget itself) is sent to the parent frame.

You don’t even notice there’s been any iframe connection, and your application code stays clean and plattform-independent.

BTW- Apotomo internally uses responds_to_parent to handle the upload. Nice work, guys!