I wasn’t at the WWDC, but even if I had been there, I probably would have missed
this too: Sproutcore.
Because of MobileMe and Live Mesh (the latter being Microsoft’s latest weapon to be a big boy on the internet, and I predict this time they will finally succeed big time), I found out that MobileMe is actually based on this open source javascript framework named Sproutcore.
You have to look for yourself what it’s all about. This is not like Prototype, jQuery or all those others. This takes MVC to the web browser, advocating fat clients. It does this with Cocoa inspired features.
I wanted Sproutcore to communicate with my rails app. It’s not as obvious at the moment unfortunately. In rails follow these steps:
rails contacts
cd contacts
Edit /config/routes.rb to look like this:
ActionController::Routing::Routes.draw do |map|
map.connect 'sc/:controller/:action'
end
In other words, all sproutcore ajax calls will be expected to hit our site relative to /sc.
Create a simple models file:
class Contact < ActiveRecord::Base
end
Create a migrations file:
class CreateContacts < ActiveRecord::Migration
def self.up
create_table :contacts do |t|
t.string :first_name, :last_name
t.timestamps
end
end
def self.down
drop_table :contacts
end
end
Run rake db:migrate. The contacts table is now created. Run script/console.
And then create two contacts so we have some data:
Contact.create(:first_name => "Lawrence", :last_name => "Pit")
Contact.create(:first_name => "Holy", :last_name => "Cow")
Exit the console. Now for our controller:
class ContactsController < ApplicationController
def list
contacts = Contact.all(:order => params[:order])
respond_to do |wants|
wants.js {
records = contacts.map do |contact|
{ :guid => contact.id,
:type => contact.class.name,
:firstName => contact.first_name,
:lastName => contact.last_name
}
end
render :text => { :records => records, :ids => contacts.map(&:id) }.to_json
}
end
end
end
Sproutcore will send a Ajax GET request like http://localhost:3000/sc/contacts/list?order=id. So we only need a wants.js block. The above code can be generalized with helper methods to make this more DRY for our other controllers, but that’s for later…
On the rails side we’re pretty much done. Fire up script/server and test the above URL. You should see a simple json formatted string as output with the two contacts you created in the database. Keep your rails server running…
Now to sproutcore. The easiest way to show this is by checking out the sproutcore-samples:
cd ..
sudo gem install sproutcore
git clone git://github.com/sproutit/sproutcore-samples.git
cd sproutcore-samples
git submodule init
git submodule update
sc-server
Now point your browser to http://localhost:4020/contacts. You should see a simple demo of sproutcore showing a few contact persons. The persons you see are loaded from fixtures by sproutcore. But we want our contacts from rails. To do this, follow these steps:
open /clients/contacts/core.js. Add this line to the end:
Contacts.server.set("urlFormat", "/sc/%@/%@");
or alternatively, create the server like this:
server: SC.Server.create({ prefix: ['Contacts'], urlFormat: “/sc/%@/%@” }),
This basically tells sproutcore that when a Ajax request is made the url should look like /sc/<controller>/<action>.
Next, edit /clients/contacts/main.js. There’s a line that says to load the contacts from the fixtures (as defined in /client/contacts/fixtures/contact.js). But we want the real data. So replace that line:
// Contacts.server.preload(Contacts.FIXTURES);
Contacts.server.listFor({recordType: Contacts.Contact});
This basically says that when the page is loaded it should do an Ajax GET request to get the list of contacts.
Edit /clients/contacts/models/contact.js, and add the lines that define dataSource and resourceURL:
Contacts.Contact = SC.Record.extend(
/** @scope Contacts.Contact.prototype */ {
dataSource: Contacts.server,
resourceURL: 'contacts',
fullName: function() {
return [this.get('firstName'), this.get('lastName')].compact().join(’ ‘);
}.property(’firstName’, ‘lastName’)
});
The value for resourceURL is what is used in the URL to make the call to rails. The datasource tells which server to use when sending the Ajax requests. Aside note: I would expect future versions of sproutcore wouldn’t need these two lines as they could be defaults.
And now the last part, the real tick to this whole thing:
# This will proxy all requests to /sc/* -> http://localhost:3000/*
proxy '/sc', :to => 'localhost:3000'
Update (thnx joel): this piece goes into the file sproutcore-samples/sc-config.
This tells sc-server to send any requests that start with /sc to http://localhost:3000 which runs our rails server.
Now refresh your browser at http://localhost:4020/contacts and lo and behold, the contacts are now coming from rails.
Last note: currently Sproutcore in not at v1.0, and it’s REST API is not well developed. I’m pretty sure this will be fixed quite soon though. This is a winner!
