Quantcast

It’s often useful to disable ActiveRecord callbacks such as :after_save when migrating data. It’s rather easy to do:


Foo.after_create.clear
Foo.after_save.clear
... migration code ...

If you only need to disable certain actions, it’s also trivial:


Foo.after_save.reject! {|callback| callback.method.to_s == 'some_method_name' }

This sort of thing should never be used in application code, if you’re doing this then your model is broken. However, it’s great for data migrations.

IRC question of the day

January 9th, 2009

Question:

_adc: I'm doing compiling some reports on various database records based in whatever
 model the user chooses... Is there a better way to figure out which models are in 
existence than http://pastie.org/356630 ?
_adc: I'm looking for an array of all models currently in existence.

Answer:

ActiveRecord::Base.subclasses_of(ActiveRecord::Base)

~/projects/learnhub$ ./script/console 
Loading development environment (Rails 2.1.1)
>> ActiveRecord::Base.subclasses_of(ActiveRecord::Base).collect {|c| c.to_s }
=> ["CGI::Session::ActiveRecordStore::Session", "ContactPostCreationNotification", .....]

Phusion Passenger is the best option for hosting Ruby based web apps (anything that uses Rack is compatible). When used with Ruby EE to serve Ruby on Rails applications it will consume up to 33% less memory than other servers such as Mongrel.

Not everything is kittens and rainbows however, as Passenger won’t prevent your app from choking your server if you consume too much memory (via memory leaks in your app, etc). Schedule this script to run every couple of minutes to kill any Passenger processes are consuming too much memory. Passenger will automatically start new ones as needed. You’ll have to figure out for yourself how much is “too much”. In my case it’s 200 MB.

It’s also useful to know how many process Passenger is using, so you can increase the MaxPoolSize when traffic increases. I use Munin to track system statistics and have written two wrappers around the Passenger system tools. The first wraps passenger-memory-stats and the second wraps passenger-status

The result are graphs such as these:

Munin graphs can be extremely helpful when tracking down system performance issues. I highly recommend it.

TexHub: A math equation service

December 29th, 2008

Carsten and I recently launched TexHub which is a little service for serving up latex equations as images. It’s pretty simple, just Base64 + URI encode latex string and append it to a URL. It’s extracted from our math equations feature on Learnhub

For example:

e=MC2

A more complex example: F(x) = \\int_{-\\infty}{a} f(t)dt + \\int_{a}^{x} f(t)dt

We haven’t done much with the front end yet as we’ll primarily be using it as a service, so the focus has been on speed. I wrote the web interface using Sinatra which turned out to be perfect for this sort of app. I plan on writing more micro apps in the future with Sinatra, perhaps the next thing will be the Ruby version of Tilomino which has been sitting untouched for two years….

Irony

August 25th, 2008

Glad to know that MS still considers that IE 6.0 is a ‘recent browser’ (it’s 7 years old, which is ancient in internet years).

Update: I’ve added benchmark numbers for JRuby 1.1.3

I’ve been messing with RubyRPS (Rock, paper scissors) lately, it’s a ton of fun! I thought it might be cool to benchmark the progression of Rubinius, and that little experiment turned into a full blown ruby interpreter shootout. Sure, this is hardly fair since RPS doesn’t use much in the way of complicated stuff (lots of loops over array, etc), but most benchmarks are bullshit anyways. I just want my RPS bots to run fast!

Here are the versions I tested.

  • ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0] (macports)
  • ruby 1.8.7 (2008-06-20 patchlevel 22) [i686-darwin9.3.0] (macports)
  • ruby 1.9.0 (2008-03-01 revision 15664) [i686-darwin9.4.0] (macports)
  • ruby 1.9.0 (2008-07-25 revision 18218) [i686-darwin9.4.0] (snapshot 1.9.0.3)
  • Rubinius 0.9.0 (ruby 1.8.6 compatible) (ffb998bf5) (08/07/2008) [i686-apple-darwin9.4.0] (from trunk)
  • JRuby 1.8.6 (2008-08-07 rev 6555) [i386-jruby1.1.1] (macports)
  • MacRuby version 0.3 (ruby 1.9.0 2008-06-03) [universal-darwin9.4] (downloaded binary)

Benchmarking is rather simple:


# time ruby ./run.rb
# time ruby1.8.7 ./run.rb
# time ruby 1.9 ./run.rb
# time rubinius ./run.rb
# time jruby ./run.rb
# time macruby ./run.rb

Interpreter Memory Usage Real User System
Ruby 1.8.6 3MB 0m36.183s 0m35.426s 0m0.241s
Ruby 1.8.7 10MB 0m17.778s 0m17.086s 0m0.154s
Ruby 1.9.0 11MB 1m17.092s 0m53.843s 0m22.234s
Ruby 1.9.0.3 10MB 0m10.350s 0m9.911s 0m0.111s
JRuby 1.1.1 28MB 0m18.023s 0m16.198s 0m0.417s
JRuby 1.1.3 28MB 0m18.622s 0m17.482s 0m0.321s
Rubinius 26MB 0m42.836s 0m41.556s 0m0.479s
MacRuby 0.3 476MB 0m42.471s 0m40.302s 0m0.987s

How about a threaded run just for fun?


# time ruby ./run.rb --threaded
# time ruby1.8.7 ./run.rb --threaded
# time ruby 1.9 ./run.rb --threaded
# time rubinius ./run.rb --threaded
# time jruby ./run.rb --threaded
# time macruby ./run.rb --threaded

Interpreter Memory Usage Real User System
Ruby 1.8.6 4MB 1m12.343s 1m9.703s 0m0.695s
Ruby 1.8.7 13MB 0m18.019s 0m17.561s 0m0.188s
Ruby 1.9 13MB 1m18.341s 0m54.516s 0m21.947s
Ruby 1.9.0.3 13MB 0m10.505s 0m10.013s 0m0.126s
JRuby 1.1.1 34MB 0m17.048s 0m22.013s 0m1.890s
JRuby 1.1.3 31MB 0m15.630s 0m22.580s 0m1.475s
Rubinus 52MB 0m43.745s 0m41.893s 0m0.591s
MacRuby 0.3 Error! stack level too deep (SystemStackError)

Conclusion

Ruby 1.9 runs RPS really fast. You may have to compile it yourself for now if you’re on a Mac, since the version in Macports does have some issues. Also, I’d recommend that anyone who is still running Rails apps on 1.8.6 to move to 1.8.7 to for an increase in speed. We’ve been using 1.8.7 to run Learnhub for a few weeks now and have noticed a decrease in memory leaks as well. Be sure to check for compatibility with your Rails app though, 1.8.7 doesn’t work with some older versions of Rails.

Surprises

I was surprised that Jruby did so well. It performs just as well as MRI 1.8.7 (with about double the memory usage). I was expecting the interpreter startup time to hold Jruby back, but that didn’t turn out to be the case. Rubinius also performed a bit better than expected (they’ve been working on correctness rather than speed thus far). It wasn’t much slower than MRI 1.8.6, although it consumed far more RAM. My understanding is that the VM is currently being rewritten, so I’ll run a few more tests when it’s released.

MacRuby is also an interesting project, with a goal of porting MRI 1.9 to run directly on top of Mac OS X core technologies such as the Objective-C common runtime and garbage collector, and the CoreFoundation framework. It’s very much a work in progress at this point.

I just wanted to read some comments on a MSN Money article. I got this:

Microsoft FAIL.

Counter caches in RoR eliminate the need to issue an sql query to determine the size of an associated collection. Using counter cache is quite simple. Here’s an example:


class Author < ActiveRecord::Base
  has_many :books
end

class Book < ActiveRecord::Base
  belongs_to :author, :counter_cache => true
end

add_column :authors, :books_count, :integer

Author.first.books.count  # gets the value from the books_count column, 
                              # rather than doing an sql count

There’s a problem if you use this alongside acts_as_paranoid. AAP is a plugin that provides ‘soft delete’ functionality. In order to achieve this, AAP overrides AR finder methods to check the ‘deleted_at’ column to determine if a record has been ‘deleted’. Due to a condition placed on the count (counting only undeleted objects), the counter cache is not used and instead an sql statement is issued.


class Author < ActiveRecord::Base
  has_many :books
end

class Book < ActiveRecord::Base
  acts_as_paranoid
  belongs_to :author, :counter_cache => true
end

Author.first.books.count # SELECT count(*) AS count_all FROM `books` 
                             # WHERE (`books`.author_id = 11524) AND 
                             # (`books`.deleted_at IS NULL OR 
                             # `books`.deleted_at > '2008-07-27 13:27:22') 

Deleting an object from a ‘paranoid’ collection will still do the right thing (decrement the counter cache), making this easy to fix. You just have to add your own count method for the collection.


class Author < ActiveRecord::Base
  has_many :books do
    def count
       books_count
    end
  end
end

Author.first.books.count  # calls the count method, returning
                       # the books counter 

This is also published on Learnhub

Nginx + HaProxy gotcha

July 22nd, 2008

I’ve recently switched from using a straight up Apache mod_proxy + mongrel setup to Nginx + HaProxy +mongrel. Basically, mod_proxy is dumb as shit, and should never be used with mongrel + rails, especially with better options like Passenger and HaProxy.

Why does mod_proxy suck? Take a look for yourself:


[8030/5/247]: handling 127.0.0.1: GET
[8031/6/134]: handling 127.0.0.1: GET
[8032/2/160]: handling 127.0.0.1: GET
[8033/0/93]: idle
[8034/10/128]: handling 127.0.0.1: GET
[8036/2/124]: handling 127.0.0.1: GET
[8035/0/110]: idle
[8037/0/101]: idle

Look at this garbage. There are three idle mongrels even though the other five have 25 requests to be processed.

Whats great about HaProxy is that it will queue up requests and only distribute them to idle mongrels. It translates into way better response times under load. Add Nginx, which is way easier to configure that Apache, allowing me to easily setup things like sending known ‘slow’ requests to separate mongrels and it’s a big win. As a bonus, haproxy has a great status tool, which gives a quick overview of your proxy clusters.


One little problem …

The gotcha when I initially switched over was that exception_notifier stopped sending me error emails, in fact the errors were being displayed to the user. What the hell?

Exception notifier looks at the incoming IP address. If it’s local (aka: 127.0.0.1), it’s assumed that the user is a developer, so it won’t email the exception to you. haproxy was sending nginx’s IP address, rather than the forwarded client address. The problem was that I had configured both nginx and haproxy to forward headers.

haproxy.conf:

option          forwardfor    # enable insert of X-Forwarded-For headers

nginx.conf

proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

Removing the header forwarding in the haproxy configuration solved the problem. You only need to set the X-Forwarded header in Nginx (or Apache or Pound or whatever front end you choose). Setting it in Haproxy as well will over write the header with one containing the IP of the front end. Since I have Nginx and Haproxy running on the same machine, that IP is 127.0.0.1, which broke the exception_notifier.

This is also published on Learnhub

Ruby Fringe

July 21st, 2008

Ruby Fringe wrapped up today and it was incredible. All of the presentations were compelling, the food was great and the parties were tons of fun. I met a ton of interesting people (who are way smarter than me), and find myself exhausted and happy.

Congratulations goes out to Pete, Meghann and the rest of the Unspace for pulling together such a great event.

I finished updating Learnhub to run on Rails 2.1. I wrote an article about a few things I learned along the way: Upgrading non-trivial apps to Rails 2.1

If you’re getting annoying exception notifications, generated by a client named “Microsoft Office Protocol Discovery”, or even “Microsoft Data Access Internet Publishing Provider Protocol Discovery” this will help.

http://rails.learnhub.com/lesson/page/2329-dealing-with-microsoft-office-protocol-discovery-in-railsv

Fun with Learnhub

June 11th, 2008

We finally have launched the new Learnhub homepage after spending a lot of effort on it. It looks great!

Also, TechCrunch posted a positive article on Learnhub Check it out!

Railsconf 08 on video

June 3rd, 2008

There were some great interviews recorded at Railsconf, and Rails Envy release some new videos. Here they are:

Session Store Switching

May 21st, 2008

I wrote a short article about a little gotcha, and the solution to it when switching your rails session store. Check it out: http://rails.learnhub.com/lesson/page/1858-how-to-switch-your-default-session-store

Everyone loves git (unless you love mecurial), and svn is so passe, so it’s time to hop on the bandwagon!

Step 1: Install Git. I use macports.

# sudo port install git-core +svn

Others may want to use one of these commands:

# sudo apt-get install git-core
# yum install git-core
# emerge -av git
# sudo pkg_add -i git-svn  
# sudo pkg_add -r git

Step 2: Check out your svn project with git. This may take a while, my project took about 20 minutes and it has 1300+ commits.

# git-svn clone https://svn.yourhost.name/projectname projectname.git

Step 3: Get any commits that may have been made to your subversion repo while you were exporting it.

# git-svn rebase

Now you’ve got a functional git clone of your subversion repo. git commands are very similar to svn commands. For example:

# git commit -a -m "This is a commit message" 
# git help  (to learn about more commands)

If you want to commit the changes you have made to your git repo to your svn repo, it’s quite easy:

# git-svn dcommit

This article is also published on Learnhub

Rails partials are are fragments of template code that can be inserted into a view. They can really simplify template code, by factoring out repeated code.

For example, I often put forms into a partial so that the form can be shared be create and edit views:

quizzes/new.html.haml
= error_messages_for :quiz
- form_for :quiz, @quiz, :url => quizzes_path, :html => {:method => :post} do |form|
  = render :partial => 'quizzes/form', :locals => {:form => form}
  = submit_tag 'Create'
quizzes/edit.html.haml
= error_messages_for :quiz
- form_for :quiz, @quiz, :url => quiz_path(@quiz), :html => {:method => :put} do |form|
  = render :partial => 'quizzes/form', :locals => {:form => form}
  = submit_tag 'Update'

Many (most) people put the render call directly in their templates. This is not a good idea! What if you want to change the template path, or conditionally render a different template in certain conditions? Now you've got to repeat yourself in both templates, and that's bad news.

A simple way to fix this is to *always* use a helper to render the partial. That way any changes can be made in one place, and it also a great place to store any messy conditional logic so that it doesn't clutter up your templates.

quizzes/new.html.haml
= error_messages_for :quiz
- form_for :quiz, @quiz, :url => quizzes_path, :html => {:method => :post} do |form|
  = quiz_form(form)
  = submit_tag 'Create'
quizzes/edit.html.haml
= error_messages_for :quiz
- form_for :quiz, @quiz, :url => quiz_path(@quiz), :html => {:method => :put} do |form|
  = quiz_form(form)
  = submit_tag 'Update
quizzes_helper.rb
def quiz_form(form)
   render :partial => 'quizzes/form', :locals => {:form => form}
end

Now if I want to do something, like say render a different form depending on a user's preference, it's easy to do.

quizzes/new.html.haml
= error_messages_for :quiz
- form_for :quiz, @quiz, :url => quizzes_path, :html => {:method => :post} do |form|
  = quiz_form(form, current_user)
  = submit_tag 'Create'
quizzes_helper.rb
def quiz_form(form, user = nil)
   if(!user.nil? && user.wants_advanced_quizzes))
     render :partial => 'quizzes/advanced_form', :locals => {:form => form}
   else
     render :partial => 'quizzes/form', :locals => {:form => form}
   end
end
This article is also published on "Learnhub":http://rails.learnhub.com/lesson/page/3400-calling-partials-through-helpers

IE8 beta is out

March 5th, 2008

A lot of people were really optimistic when it was announced that IE 8 would render Acid2, something that Firefox2 can't even do (Firefox beta3 can however).

It was thought that Microsoft was finally catching up in terms of standards compliance with the other popular browsers. To bad that rendering Acid2 doesn't really mean that the browser is 'standards compliant'. It just means that it can render the subset of the standard that Acid2 tests. With the release of Acid3, it looks like Microsoft focused solely on rendering Acid2, not on the standards in general. IE8 scored a poor 17/100 on Acid3.

Webkit Acid3 result

On the opposite end of the spectrum, Apple's latest Webkit beta scored 86/100.

Webkit Acid3 result

Learnhub launches!

March 4th, 2008

The entire Savvica team has been busy since November building Learnhub, which we launched today at noon. We've had a great time building it, and have a ton of ideas for future features. Check it out!
Learnhub Screenshot

A gotcha

February 27th, 2008

Just got bitten by this. Observers are not called when deleting an object via a through collection.

An example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

class Newsletter < ActiveRecord::Base
  has_many :subscribers
  has_many :users, :through => :subscribers
end

class SubscriberObserver <  ActiveRecord::Observer
  def after_destroy(subscriber)
    # do somethng
  end
end

# case 1
# deletes a subscriber object. after_destroy is not called
@newsletter.users.delete(user) 

# case 2
 # after_destroy is called.
subscriber = @newsletter.subscribers.find(:first, :conditions => ["user_id = ?", user.id])
subscriber.destroy unless subscriber.nil?  

In both cases a subscriber object is being destroyed, but the observer is being called only in the second scenario. I'll have to look into patching this when I get a chance ....

One thing I hate about Rails ...

February 26th, 2008

One thing I truly hate in Rails is ActionMailer. It sucks.

First off (admittedly a minor point), mailers are stored in app/models, even though they are basically a pseudo controllers, complete with view templates (stored in app/views). It makes no sense.

Secondly, ActionMailer does not have access to named routes or any view helpers. The 'rails way' would be to call the mailer from a controller, passing the URL as an argument which is just stupid in my opinion. Most of the time I send an email in an application it is due to a change in an model's state, not due to a specific controller interaction. A nice way of doing this through use of active record observers (which also don't have access to routes).

This means I generally end up hardcoding the URLs in the mailer. It wouldn't be a huge deal if my test coverage checks that the hardcoded url in the email body matches a generated one. But to do that you'll need to write integration tests rather than the default 'ActionMailer' tests that are auto generated. The whole mess frustrates me unlike anything else in Rails.

Merb seems to get it right with its Merb::MailController. Perhaps something similar could be added to Rails via a plugin?

Immutable Attribute Plugin

November 14th, 2007

A new Ruby on Rails validation plugin that allows you to mark model attributes as immutable. Rails surprisingly does not include a validation method to make a model attribute immutable. (That is, the attribute can not be changed after it is set the first time.) I created this validation plugin to help that. Check out my post on the Savvica blog.

Updates and such ...

November 3rd, 2007

I resigned my position with TSOT a few weeks ago, and have joined John and Malgosia at Savvica. We're going to be building some pretty cool stuff!

Last week Carsten and I were able to knock off a beta of Languify, which is a tool to help software developers to collect and manage language translations for software localization. It's pretty simple for now, but we've got a lot of cool ideas that we'll be implementing in the near future. Keep an eye on it!

Rails on OpenBSD

August 10th, 2007

It's extremely easy.
  1. Install your favorite database server. My favorite is Postgres.
    
    
    $ sudo pkg_add -i postgresql-server
  2. Install the ruby database bindings for your favorite database server.
    
    
    $ sudo pkg_add -i ruby-postgres
  3. Install rails.
    
    
    $ sudo pkg_add -i ruby-rails
That's it!. pkg_add is a great tool (much like apt on debian systems) that takes care of all of the package dependancies.

haml & sass

August 9th, 2007

haml is template languages for Ruby on Rails. It's a plugin that provides an alternative to Rails' native view templating library erb. sass is included with haml, and provides templating for css files. Through clever usage of whitespace, both remove much of the verbosity of html and css (<>, end tags ,etc) , providing a concise way of creating templates. For example, take this typical layout template:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title><%= controller.action_name %></title>
  <%= stylesheet_link_tag 'mycss' %>
</head>
<body>
  <p style="color: green">
    <%= flash[:notice] %>
  </p>
  <div id="header">
     <h1>Header</h1>
  </div>
  <div id="content">
    <%= yield  %>
  </div>
</body>
</html>
Here's the same thing in haml. Notice the usage of whitespace to delimit block the nesting of the code. Also, regular html can be mixed in as well.
1
2
3
4
5
6
7
8
9
10
11
12
13

!!!
%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}
  %head
    <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
    %title= controller.action_name
    = stylesheet_link_tag 'mycss'
  %body
    %p{:style => "color:green"}= flash[:notice]
    #header
      %h1 Header
    #content
      = yield
There are a few benefits to this:
  • the information density is greater, so more of the template is visible on screen.
  • less characters to type, so less chance to make a typo
  • nesting is clearly visible, and no more issues with missing end tags.
sass is similar to haml in that it uses whitespace for nesting, eliminating verbosity. In my next article, I'll explain the benefits and usage of Sass.

Facebook Garage - Part 6

August 7th, 2007

Demo: Carpool by: Rajat Suri

Rajat explains how he produced the idea of Carpool, and how Facebook was the perfect (only?) platform to build it. Facebook already has the users, and it connects people that already trust each other (at least on some level).

The app is pretty cool, it shows rides offered and needed, how many miles the user has travelled, and how many CO2 emissions have been avoided by carpooling. Rajat should talk to Zero Footprint about this :)

Demo: My Aquarium by Greg Thomson

This developer's applications have a total of 2.6 million users and 75,000 new users per day. (wow!)

Greg talked about profile updates, which apparently have a failure rate of 5%. He solved the problem by having a queue that runs all of the time, attempting requests until they succeed.

Facebook Garage - Part 5

August 7th, 2007

Updating the Facebook Profile. by Colin Smillie

Rules:
  • content rules
    • no iframes, or auto-running flash
  • display rules
    • consistent presentation and user experience
Caching
  • The profile page is cached, so your app must notify facebook in order to update the profile page.
  • See the fb:ref method for updates.
  • multiple handles are possible, so you could update many profiles at once (think of a horrorscope application, only 12 updates would need to be made for many users

Application Demo: "My Free Stuff", by: Ricardo Covo

Ricardo presents his application which was developed with MS tools (dotNet + SQL Server). He also uses iframes, which seems to be less common. Like Rails, dotNet has an API wrapper (several) for ease of use.

Ricardo found the facebook platform to be extremely easy to develop for, and the api wrappers provide seamless integration into your own platform of choice.

Facebook Garage - Part 4

August 7th, 2007

FQL: Overview by Craig Saila

Facebook API calls are just embedded FQL calls.

Advanatages:
  • common syntac for all methods
  • condense facebook queries
  • reduce response size
FQL is very similar to SQL. Sub selects are allowed, etc.

Ex: SELECT current_location FROM user WHERE uid = 324324. This will return an XML response.

There are about two dozen tables that can be queried. The users table is most often queried.

FQL contains some helper functions that help with queries. It's quite PHP like.

You can only query against "indexable" columns in your where statement. You need at least one in your query.

FQL is designed to be efficient, so no JOIN, ORDER BY, GROUP BY or LIMIT. Each FROM can only reference one table. You must also specify each field that you want the query to return ("SELECT *" is not allowed). Sorting of data, etc must be done on the application level.

Tips:
  • Use the developers tools (fql.query)
  • Read the API docs
  • Share what you learn on your blog or wiki

Facebook Garage - Part 3

August 7th, 2007

FBML (Facebook Markup Language) introduction by Sunil Boodram

FBML is used to tap into Fackbook elements to ease application creation. It's somewhat similar to HTML. Ex: <fb:gogle-analytics> will generate the proper html to add Google Analytics tracking into your app.

Many of the HTML tags work in FBML. Notable exceptions include <script> and <style>. You may use css in your app, but it will be altered in order for it to not break the look of facebook itself.

Facebook provides an FBML test console, which saves repeated uploads to your dev server when building an application.

Check the FBML documentation for existing tags, they make life much easier!

Jay Goldman explains the anatomy of a facebook application.

Applications go into the application directory
  • make it look pretty!
  • use good keywords, be descriptive
The about page:
  • This page can be really used to sell users on the app. Make it convincing!
Application left nav:
  • The icon and name are important so that the user remembers what it looks like so they can find it
Canvas
  • Where your application's app is displayed
  • Put compelling content on the canvas page, ex: information from your friends
Dashboard
  • should contains the user's data, rather than the data from their friends
Privacy settings
  • consider what will happen if the user turns any of them off
Infecting
  • profile action links
  • news feed
  • message attachments .. you can attach pretty much anything!
  • requests: you can only invite ten friends per day
The Facebook developer garage came to Toronto this evening, at MARS. It's a popular event as the main presentation room is packed, and a second room is setup with an audio/video feed. Both CBC radio and CityTV News have reporters covering the event.
  • Facebook has 15 billion page views/month
  • 2400+ applications, 100 million downloads
  • This is the 1st facebook dev garage in Canada to encourage more developers to write apps on facebook

Highlights from the first presentation:

Facebook platfom
  • Canada has 10% of all facebook developers
  • Toronto is one of the top ten cities for facebook developers
  • 33 million active users!
  • 150, 000 new users per day
  • 1,700 applications with more than 100 users
  • Facebook social graph
    • Identity
    • Information
    • Social Context
  • Ninja tricks
    • More integration points == better
    • News feed is still quite important
  • Profile integration
    • Feed shows installations and application actions (add a photo, etc)
    • Recent Interactions
    • Recently Added Content
    • Social Relevancy
    • Content for expression (not consumption)
    • Timestamps are important (when did it happen?)
    • Users want to show off
  • Canvas Page Engagement
    • Keep the captive audience
    • Use social comparisons
    • Increase engagement
    • Action buttons are good == big buttons that will generate events that go into the feed
  • Lesser used integration points
    • Message
    • Composer
    • Profile actions
    • Wall
    • Share
  • Mass distribution
    • at least 75% users have installed an app
  • Feed the mini-feed
    • Primary Actions
    • Temporal
    • Include friends
    • Increase Relvancy
    • Utilize Call-to_action buttons
  • Build Apps to promote core business
    • Cross-promote
    • Interactive Cross-promotion (ex: iLike)
  • New Opportunities Virtual currency
    • incentive based actions
    • self promotion
    • social promotion
    • ex: pet someone else's pet and earn money. excahnge money to give gifts to other user's pet
    • so basically give social capital == rewards for interacting with the site
    Ad Networks
    • apps allow ad network to advertise on your app's canvas space
    • high cpm's ($20)
  • APIs on top of the API
    • ex: post on SuperWall instead of Wall
  • Metrics to think about
    • the facebook effect (aka: the slashdot effect)
    • provides dramatic traffic growth to external sites
  • Virality metrics
    • Installed base
    • Outgoing impressions
    • Conversions
  • Engagement metrics
    • repeat sessions, etc

There are more articles about the presentations listed below:

IE and innerHTML stupidity

August 7th, 2007

In today's Ajaxy web, web developers find themselves dynamically displaying content more than ever. One issue that may bite you is the IE 6 implementation of innerHTML. For example:
1
2
3
4
5
6
7
8
9
10


new Ajax.Request(url, { 
                      method: 'post',
          onComplete: function(request)
          {   
              $('mydiv').update(request.responseText);
                                            // .... do more stuff, etc
          }
         });
In IE 6 you may find that the code is throwing an error on the update call (which in IE uses innerHTML). The problem is that the html returned by the Ajax call is not technically valid. It may contain <style> or <script> tags for example, or perhaps the target element is does not allow inner blocks (<p> for example). The worst part about it is that the error does not contain any sort of helpful error message to help you out. Also, the same code will likely work fine in other browsers such as Safari or Firefox. So if you happen to run into problems updating an element in IE, take a close look at the content that you're trying to insert. IE 6 is very stringent about what it allows.

Railsconf 2007

May 21st, 2007

I have spent the past four days in Portland OR, attending Railsconf. This week included a couple of firsts for me:
  • It was the first tech conference that I've attended
  • My first trip to the west coast. Well, to be truthful, my first trip anywhere west of Sarnia! I need to travel more ....

Highlights

  • David Heinemeier Hansson's keynote on friday. Rails 2.0 won't be a revolution as much as an evolution, but it's shaping up to be another fantastic release
  • Jim Weirich's presentation "Spam I Have Known". Jim is an excellent speaker, and he explained the issues involved in eliminating wiki spam in an entertaining fashion.
  • The Open Mic sessions. They were a fair bit shorter than the ones given at Demo Camp (5 minutes rather than 15) which worked quite well. Statisfy.net was cool, if gimicky.
  • The Rails Way talk/Q & A with Jamis Buck and Michael Koziarski. They were a real life version of their fantastic blog, The Rails Way, and they also held a Q & A session, with questions posted via IRC. They pointed out the proper way to use 'map' in routing which prompted me to overhaul all my routes utilizing 'map.with_options'.
  • "Choose Your Battles and LetIt::REST" by Hampton Catlin and Jeff Hardy. Their idea of making controllers 'resourceful' looks REALLY promising. I can't wait until it's released
  • Dave Thomas's closing keynote. He challenged the Rails community to innovate, comparing the way that we deliver web applications now to the mainframes that served applications in the 1970's.

Lowlights

  • The presenter for "Rails Security: Theory and Practice" was a no show. Maybe he thought that his former roommate (who was in attendance) was going to try to shake him down for being a deadbeat ex-housemate